💡 前言
你是否遇到过这样的困惑:
- “我明明写了这个样式,为什么页面上没效果?”
- “为什么加了 .class 还是被另一个 .class 覆盖了?”
- “是不是只要我加足够多的类名,就能赢过 ID 选择器?”
这一切的背后,都是 CSS 优先级(Specificity) 在起作用。
浏览器就像一位严格的法官,当多个规则指向同一个元素时,它需要根据一套明确的“法律”来决定听谁的。今天,我们就来揭秘这套“法律”。
1. 核心原则:四阶权力等级 👑
CSS 优先级的计算基于一个四位数的权重系统。我们可以把它想象成四个不同等级的“官员”,级别高的永远压倒级别低的。
| 第一级 | 行内样式 (Inline Styles) | <div style="color: red;"> | 1000 |
| 第二级 | ID 选择器 | #header | 100 |
| 第三级 | 类/伪类/属性选择器 | .btn, :hover, [type="text"] | 10 |
| 第四级 | 标签/伪元素选择器 | div, p, ::before | 1 |
| 特殊 | 通配符/组合符 | *, +, >, ~, (空格) | 0 |
⚠️ 注意:
- 这不是十进制数!0, 0, 1, 0 (10) 永远小于 0, 1, 0, 0 (100)。哪怕你有 100 个类名,也打不过 1 个 ID。
- !important 不属于这个计算体系,它是“核武器”,凌驾于所有优先级之上(除非另一个也有 !important 且优先级更高,或后者也是 !important 但后定义)。
2. 如何计算优先级?🧮
计算优先级的步骤非常简单:统计选择器中各等级组件的数量。
📝 计算公式
(行内样式, ID数量, 类/伪类/属性数量, 标签/伪元素数量)
💡 实例演练
假设我们有以下 HTML:
<div id="container" class="box">
<p class="text">Hello</p>
</div>
案例 1:简单对比
/* A */
p {
color: blue;
} /* 权重: 0,0,0,1 -> 1分 */
/* B */
.text {
color: red;
} /* 权重: 0,0,1,0 -> 10分 */
结果:B 胜出,文字变红。因为 10 > 1。
案例 2:组合选择器
/* A */
#container .text {
color: green;
} /* 权重: 0,1,1,0 -> 110分 */
/* B */
div p.text {
color: yellow;
} /* 权重: 0,0,1,2 -> 12分 */
结果:A 胜出,文字变绿。因为 110 > 12。
解析:A 有 1 个 ID + 1 个类;B 有 2 个标签 + 1 个类。ID 的权重远高于标签。
案例 3:类名堆叠能赢 ID 吗?
/* A */
#myId {
color: black;
} /* 权重: 0,1,0,0 -> 100分 */
/* B */
.c1.c2.c3.c4.c5.c6.c7.c8.c9.c10 {
color: purple;
} /* 权重: 0,0,10,0 -> 100分? NO! */
纠正:B 的权重是 0,0,10,0。在比较时,先比第二位(ID位)。A 是 1,B 是 0。A 胜出!
即使你有 1000 个类名,只要没有 ID,就永远赢不了一个 ID 选择器。
3. 同级优先级怎么办?“后来者居上” ⏳
如果两个选择器的优先级完全相同,浏览器会遵循**层叠(Cascading)**规则:
后定义的样式覆盖先定义的样式。
/* 写在前面 */
.btn {
color: blue;
}
/* 写在后面 */
.btn {
color: red;
}
结果:文字变红。因为它们在源码中位置靠后。
注意:这与 HTML 中 class 的顺序无关,只与 CSS 文件中规则出现的顺序 有关。
<!– class 的顺序不影响优先级 –>
<div class="b a"></div>
.a {
color: blue;
}
.b {
color: red;
} /* 胜出,因为 .b 在后 */
4. 特殊角色:!important ☢️
!important 是一个声明,它可以提升单个属性的优先级,使其忽略常规的计算规则。
#header {
color: blue !important;
}
.header-text {
color: red;
}
结果:蓝色。即使 .header-text 可能通过其他高权重选择器匹配,!important 也会强制生效。
⚠️ 滥用 !important 的危害
💡 最佳实践:
- 尽量不要使用 !important。
- 仅在以下场景使用:
- 第三方库样式冲突,且无法修改源文件时。
- 实用工具类(如 .hidden { display: none !important; }),确保其绝对生效。
5. 常见误区澄清 ❌
误区:“子选择器 > 比后代选择器 优先级高。”
- 真相:组合符(>, +, ~, )的权重为 0。它们不影响优先级计算,只影响匹配范围。
- div p (1+1=2) 和 div > p (1+1=2) 优先级相同。
误区:“:not() 伪类本身有优先级。”
- 真相::not() 本身不计入权重,但括号内的参数计入。
- :not(#id) 的权重等于 #id (100)。
- :not(.class) 的权重等于 .class (10)。
误区:“HTML 中 class 写在前面的优先级低。”
- 真相:HTML 中 class 的顺序完全不影响 CSS 优先级。只有 CSS 规则的定义顺序才影响同级权重的胜负。
6. 最佳实践:如何写出优雅的 CSS? 🛠️
保持低特异性:
- 尽量使用类选择器(.class),避免使用 ID 选择器进行样式定义(ID 留给 JS 钩子或锚点)。
- 避免过深的嵌套(如 .a .b .c .d),这会导致优先级过高且难以维护。
利用层叠,而非对抗:
- 如果需要覆盖样式,尽量使用更具体的类名,或者调整 CSS 文件的加载顺序,而不是加 !important。
使用 BEM 命名规范:
- Block__Element–Modifier。通过扁平化的类名结构,避免嵌套带来的优先级问题。
- 例如:.card__title 而不是 .card .title。
CSS Modules / Scoped CSS:
- 在现代框架(Vue, React)中,使用作用域样式可以自动隔离样式,减少全局优先级冲突。
7. 总结记忆口诀 🧠
优先级,看权重,四位数字记心中。
行内一千是第一,ID 一百紧随其后。
类伪属性一十分,标签伪元一分够。
通配组合零分算,重要声明凌驾众。
同级相比看先后,后来居上定胜负。
少用 ID 少嵌套,重要声明莫乱用。
类名平铺最优雅,维护轻松不头痛。
希望这篇文档能帮你彻底理清 CSS 选择器的优先级!如果觉得有用,欢迎点赞收藏~ 🌟

