【H5 前端开发笔记】第 24 期:CSS 层叠样式表 —— 选择器权重(Specificity)计算与 !important 优先级详解
这一期我们正式进入 CSS 层叠(Cascade) 的核心战场:特异性(Specificity) + !important。
理解了这两点,你就能彻底搞懂“为什么我的样式不生效”“为什么用了 !important 还是被覆盖”“层叠到底是怎么比的”这些永恒的迷惑。
一、特异性计算规则(2026 年最新标准,来自 MDN & CSSWG)
特异性是一个四元组(A-B-C-D),从左到右权重递减:
| 位置 | 权重值 | 对应选择器类型 | 备注(2026 年无变化) |
|---|---|---|---|
| A | 1,0,0,0 | 内联样式(style=”” 属性) | 最高,几乎无敌 |
| B | 0,1,0,0 | ID 选择器 #id | 1 个 ID = 0,1,0,0 |
| C | 0,0,1,0 | 类 .class、属性 [attr]、伪类 :hover 等 | 1 个 = 0,0,1,0 |
| D | 0,0,0,1 | 元素 div、伪元素 ::before | 1 个 = 0,0,0,1 |
计算原则:
- 从选择器的每个简单选择器分别计数,累加到对应列
:not(),:is(),:where(),:has()本身不加分,但括号里的选择器正常计分(取最高的那组用于:is()/:where())- 复合选择器(如
.btn.active)= 两个 C 类 → 0,0,2,0 - 通配符
*、+、>、~等连接符不加分 - 伪元素
::before算 D,伪类:hover算 C
常见特异性速查表(背下来就够用 95% 场景)
| 选择器示例 | 特异性值 | 十进制类比 | 备注 |
|---|---|---|---|
style="color:red;" | 1,0,0,0 | 1000 | 内联,几乎打不过 !important |
#header | 0,1,0,0 | 100 | ID |
.btn-primary | 0,0,1,0 | 10 | 单类 |
button | 0,0,0,1 | 1 | 元素 |
#header .btn | 0,1,1,0 | 110 | ID + 类 |
.card__title--large (BEM) | 0,0,2,0 | 20 | 两个类 |
article p:first-child | 0,0,1,2 | 12 | 类 + 两个元素/伪类 |
:where(#id, .class, div) | 0,0,0,0 | 0 | :where() 故意降为 0 |
:is(#id, .class) | 0,1,0,0 | 100 | 取最高(这里是 ID) |
二、!important 的优先级规则(关键!)
!important 是一个独立于特异性的炸弹,但有严格顺序:
- 先比 origin + layer + importance(是否 !important)
- 同 origin、同 layer、同 importance → 再比特异性
- 特异性还一样 → 最后比源码顺序(后面覆盖前面)
!important 层级总结表(2026 年视角)
| 优先级顺序(从高到低) | 说明 |
|---|---|
| 1. Transition 动画中的声明 | 最高(动画中 !important 也打不过) |
| 2. !important + 用户样式表 | 用户自定义样式(accessibility) |
| 3. !important + 作者样式表(我们写的) | 我们最常用的 !important |
| 4. !important + 作者层(@layer 高层) | 高层 @layer 中的 !important |
| 5. 普通声明 + 作者 @layer 高层 | 无 !important 但在高优先级 layer |
| 6. 普通高特异性作者样式 | 正常特异性比拼 |
| 7. 浏览器默认(user agent)样式 | 最低 |
一句话总结:
!important 先于 特异性生效 → 同为 !important 时,才看特异性 → 再同,才看顺序。
经典陷阱:
用了 !important 的低特异性规则,仍然会被更高层或更高特异性的 !important 覆盖。
三、实战代码演示(敲一遍最清晰)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>特异性 & !important 演示</title>
<style>
/* 层 1:低优先级基础 */
p {
color: gray; /* 0,0,0,1 */
}
/* 层 2:类选择器 */
.text {
color: orange; /* 0,0,1,0 → 胜过 gray */
}
/* 层 3:更高特异性 */
div p.text {
color: purple; /* 0,0,1,1 → 胜过单类 */
}
/* 层 4:ID */
#special p {
color: blue; /* 0,1,0,1 → 胜过上面 */
}
/* !important 登场 */
.force-red {
color: red !important; /* 0,0,1,0 + !important → 炸场 */
}
/* 更高特异性 + !important */
#special .force-red {
color: green !important; /* 0,1,1,0 + !important → 胜过上面 */
}
/* 内联样式(最高) */
/* <p style="color: black !important;"> 会赢几乎一切 */
</style>
</head>
<body>
<div id="special">
<p>普通 p → gray(被覆盖)</p>
<p class="text">有 .text 类 → orange(被更高覆盖)</p>
<p class="text force-red">.force-red !important → red</p>
<p class="force-red" style="color: black !important;">内联 + !important → black(无敌)</p>
<p class="force-red" id="special">ID + .force-red → green !important(最高特异性 !important)</p>
</div>
</body>
</html>
四、2026 年最佳实践建议(避免特异性战争)
- 尽量别用 !important(除非覆盖第三方库或 accessibility)
- 用 @layer 管理层级(现代方案,远胜 !important)
@layer base, components, utilities;
@layer base { p { color: #333; } }
@layer utilities { .text-red { color: red; } } /* utilities 层更高,覆盖 base */
- 用 :where() / :is() 控制权重
- 优先单类 / BEM / Tailwind 原子类 → 特异性可控
- 计算工具:Polypane Specificity Calculator、项目 Wallace 等
下一期预告:CSS 层叠完整流程 + @layer 实战 + @scope 新特性
有特异性计算的经典迷惑案例或 !important 救命场景,欢迎留言分享~
祝大家 CSS 权重玩得明明白白,再也不被样式“背刺”!⚖️