第8章 选择器优先级
第八章:选择器优先级
CSS 的层叠规则就像一场"权力游戏"——当多个选择器同时想要控制同一个元素的同一个属性时,谁说了算?这就是优先级要解决的问题。学会了优先级,你就能精准地控制"谁的话更大声",而不是被浏览器的默认规则搞得一头雾水。
8.1 优先级计算
8.1.1 通用选择器 * ——权重 0
通用选择器 * 的权重是最低的,几乎可以忽略不计。
1
2
3
4
5
6
7
8
9
10
| /* * 的权重 = 0 */
/* 任何其他选择器都能覆盖它 */
* {
color: red; /* 权重 0 */
}
p {
color: blue; /* 权重 1,大于 0,所以蓝色胜出 */
}
|
1
2
| <p>这段文字是什么颜色?</p>
<!-- 答案是蓝色,因为 p 标签选择器权重更高 -->
|
8.1.2 标签选择器、伪元素——权重 1
1
2
3
4
5
6
7
8
9
10
11
12
13
| /* 标签选择器权重 = 1 */
p {
color: red; /* 权重 1 */
}
div {
color: blue; /* 权重 1,和 p 一样,后写的胜出 */
}
/* 伪元素权重 = 1 */
::first-letter {
color: green; /* 权重 1 */
}
|
1
2
| <p>文字颜色?</p>
<!-- 如果只有这两个选择器,颜色取决于谁后写 -->
|
8.1.3 类选择器、属性选择器、伪类——权重 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| /* 类选择器权重 = 10 */
.btn {
color: red; /* 权重 10 */
}
/* 属性选择器权重 = 10 */
[type="text"] {
color: blue; /* 权重 10 */
}
/* 伪类权重 = 10 */
:hover {
color: green; /* 权重 10 */
}
/* 一个类选择器权重 10,直接碾压 10 个标签选择器(10 × 1 = 10),无需数量叠加 */
/* 但打不过一个 ID 选择器(100)*/
|
1
2
| <button class="btn">按钮</button>
<!-- 类选择器 .btn 权重 10 -->
|
8.1.4 ID 选择器——权重 100
1
2
3
4
5
6
7
8
9
10
| /* ID 选择器权重 = 100 */
#header {
color: red; /* 权重 100 */
}
/* 10 个类选择器(10 × 10 = 100)≈ 1 个 ID选择器(100),几乎持平 */
/* 11 个类选择器(11 × 10 = 110)> 1 个 ID选择器(100),理论上可以胜出 */
.header.header.header.header.header.header.header.header.header.header.header {
color: blue; /* 权重 (0, 11, 0, 0),略高于 ID 的 (1, 0, 0, 0) */
}
|
1
2
| <header id="header" class="header">导航栏</header>
<!-- ID 选择器 #header 权重 100 -->
|
8.1.5 内联样式(style 属性)——权重 1000
1
2
3
4
5
| <!-- 内联样式权重 = 1000 -->
<header id="header" class="header" style="color: purple;">
导航栏
</header>
<!-- style="color: purple" 权重 1000,优先级最高 -->
|
8.2 比较方法
四位数比较法是 CSS 优先级计算的官方标准方法。每一个选择器都可以转换成一个四位数 (a, b, c, d):
(a, b, c, d)
│ │ │ └── d = 通用选择器数量
│ │ └── c = 标签选择器 + 伪元素数量
│ └── b = 类选择器 + 属性选择器 + 伪类数量
└── a = ID 选择器数量
*记忆口诀:a(爱)ID(身份证)> b(杯)Class > c(菜)Tag > d(的)通用
即:ID > 类/属性/伪类 > 标签/伪元素 > 通用选择器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| /* 示例 1:#header .nav li → (1, 1, 1, 0) */
#header .nav li {
/* #header = 1个ID = 1 */
/* .nav = 1个类 = 1 */
/* li = 1个标签 = 1 */
/* 总计 = (1, 1, 1, 0) */
}
/* 示例 2:div.container #main .item → (1, 2, 1, 0) */
div.container #main .item {
/* div = 1个标签 */
/* .container = 1个类 */
/* #main = 1个ID */
/* .item = 1个类 */
/* 总计 = (1, 2, 1, 0) */
}
/* 示例 3:* body .card p → (0, 1, 2, 1) */
* body .card p {
/* * = 1个通用 */
/* body = 1个标签 */
/* .card = 1个类 */
/* p = 1个标签 */
/* 总计 = (0, 1, 2, 1) */
}
|
比较规则:依次比较 a 位 → b 位 → c 位 → d 位
1
2
3
4
5
6
7
| /* 选择器 A */
#header .nav li → (1, 1, 1, 0)
/* 选择器 B */
.sidebar .menu span → (0, 2, 1, 0)
/* 比较:a位 1 vs 0 → A 胜出!不用看后面的了 */
|
1
2
3
4
5
6
7
8
| /* 选择器 A */
.container .item → (0, 2, 0, 0)
/* 选择器 B */
ul li → (0, 0, 2, 0)
/* 比较:a位 0 vs 0 → 平局 */
/* 比较:b位 2 vs 0 → B 胜出! */
|
更复杂的例子:
1
2
3
4
5
6
7
8
| /* 选择器 A */
nav ul li a.link → (0, 1, 4, 0)
/* 选择器 B */
#nav .menu .item → (1, 2, 0, 0)
/* 比较:a位 0 vs 1 → B 胜出! */
/* B 的 ID 选择器权重更高 */
|
实战中的优先级比较:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| /* 场景:你想让 .highlight 覆盖 h1 的样式 */
h1 {
color: blue; /* (0, 0, 1, 0) */
}
.highlight {
color: red; /* (0, 1, 0, 0) */
}
/* 比较:(0, 1, 0, 0) vs (0, 0, 1, 0) */
/* a位:0 vs 0 → 平局 */
/* b位:1 vs 0 → .highlight 胜出! */
h1.highlight {
color: green; /* (0, 1, 1, 0) */
}
/* 比较:(0, 1, 1, 0) vs (0, 1, 0, 0) */
/* a位:0 vs 0 → 平局 */
/* b位:1 vs 1 → 平局 */
/* c位:1 vs 0 → h1.highlight 胜出! */
|
8.2.2 !important 优先级最高——会覆盖所有普通声明
!important 是声明级别的特殊规则,一旦加上,它就会无视选择器优先级(包括内联样式),覆盖所有普通声明。它的效力比任何选择器都高,属于"规则破坏王"。
⚠️ 注意:!important 不是选择器权重,而是声明级别的修饰符。在优先级计算中,只有普通声明才按选择器权重比较。
1
2
3
4
5
6
7
8
9
| /* 普通声明 */
p {
color: blue; /* 普通声明 */
}
/* !important 声明——无视任何选择器权重,直接覆盖 */
p {
color: red !important; /* 这条会覆盖上面的蓝色,即使蓝色来自 ID 选择器 */
}
|
8.3 !important 的使用
8.3.1 不推荐滥用——导致样式难以维护
1
2
3
4
5
6
7
8
9
10
11
| /* ⚠️ 滥用 !important 的后果 */
/* 以后无论写什么选择器都很难覆盖它 */
.super-important {
color: red !important; /* 这个红色永远无法被覆盖 */
}
/* 团队协作时会导致混乱 */
/* A 用了 !important,B 不得不也用 !important */
/* 然后 C 又用了更高优先级的 !important */
/* 最后代码变成了一锅粥 */
|
8.3.2 实际开发建议——不要用内联样式、不要用 !important、保持选择器简洁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| /* ✅ 正确的做法 */
/* 1. 用合理的优先级结构 */
.header {
color: blue; /* 基础样式 */
}
.header .logo {
color: red; /* 子元素覆盖父元素,自然而然 */
}
/* 2. 用 CSS 变量控制主题 */
:root {
--primary-color: #3498db;
}
.button {
background: var(--primary-color); /* 通过变量控制,方便切换 */
}
/* 3. 用 class 组合 */
.btn {
padding: 12px 24px;
border-radius: 6px;
}
.btn-primary {
background: #3498db;
color: white;
}
.btn-danger {
background: #e74c3c;
color: white;
}
/* 4. 必要时用 JavaScript 动态切换 class */
|
graph TD
A["!important 使用指南"] --> B["尽量避免"]
A --> C["使用场景"]
B --> B1["破坏层叠规则"]
B1 --> B2["维护困难"]
B2 --> B3["团队协作噩梦"]
C --> C1["CSS 库样式覆盖(但最好用更高优先级的方案)"]
C --> C2["打印样式强制显示"]
C --> C3["用户样式表优先级"]
style A fill:#f39c12,stroke:#333,stroke-width:3px
本章小结
恭喜你完成了第八章的学习!让我们来回顾一下这章的精华:
核心知识点
| 选择器 | 权重 |
|---|
通用选择器 * | 0 |
| 标签选择器、伪元素 | 1 |
| 类选择器、属性选择器、伪类 | 10 |
| ID 选择器 | 100 |
| 内联样式 | 1000 |
!important | 最高(声明级别,非选择器权重) |
优先级计算口诀
优先级(从高到低):
!important(声明级) > 内联样式 > ID选择器 > 类/属性/伪类 > 标签/伪元素 > 通用选择器
!important 是"规则破坏王",无论选择器强弱,一票否决。
普通声明才按下方数字比较:
内联1000 > ID100 > 类10 > 标签1 > 通用0
四位数比较法
四位数格式:(a, b, c, d)
a = ID 选择器数量
b = 类选择器 + 属性选择器 + 伪类数量
c = 标签选择器 + 伪元素数量
d = 通用选择器数量
示例:
#header .nav li → (1, 1, 1, 0)
.sidebar p → (0, 1, 1, 0)
下章预告
下一章我们将开始学习第四部分:盒模型——CSS 布局的核心。盒模型是 CSS 布局的基石,理解了盒模型,你才能真正掌握元素的尺寸计算和布局原理!