CSS选择器权重按(a,b,c,d)四位逐位比较:a为内联样式,b为ID,c为类/属性/伪类,d为元素/伪元素;高位优先,不转十进制相加。

怎么算出一个选择器的权重值
CSS选择器权重不是简单加法,而是四位数逐位比较:内联样式、ID、类/属性/伪类、元素/伪元素,对应 (a,b,c,d)。浏览器不把它们转成十进制数字相加,而是从左到右比大小——a 大就赢,a 相同才看 b,依此类推。
比如 #nav .item a:hover 含 1 个 ID(b=1)、1 个类(c=1)、1 个元素(d=1)、0 个内联(a=0),权重是 (0,1,1,1);而 .header .menu li.active a 没有 ID,但有 2 个类 + 3 个元素 → (0,0,2,3)。虽然 2+3=5 > 1+1+1=3,但 b=0 < b=1,所以后者完全压不住前者。
常见误算点:
- 把
[id="foo"]当作 ID 选择器——它只是属性选择器,只计c=1,不是b=1 - 认为
:not(.active)自身增加权重——实际只看括号里内容,:not(.active)等价于c=1 - 把组合符
>、+、~当作有分量——它们权重为 0,完全不参与计算
ID 选择器为什么经常导致覆盖困难
ID 的权重是 b=1,而类选择器最多只能堆到 c=99,但 (0,1,0,0) > (0,0,99,99) ——高位碾压,没法靠数量补。这在组件化开发中尤其危险:一个用了 #modal 的旧模块,后续任何基于类的封装都很难安全覆盖它。
立即学习“前端免费学习笔记(深入)”;
真实踩坑场景:
- 第三方 UI 库用 ID 做内部锚点或状态标记(如
#drawer-open),你写.my-drawer .content试图改样式,结果无效 - Vue/React 组件中用
id绑定 labelfor,意外让该 ID 进入全局 CSS 作用域,引发权重污染 - 调试时发现 Chrome DevTools 显示某规则“已取消”,但没报错——大概率是某个 ID 选择器在别处悄悄生效了
!important 和内联样式谁更优先
!important 是唯一能突破四位权重体系的存在:它不参与 (a,b,c,d) 比较,而是直接“终结判决”。哪怕 style="color:red" 是 (1,0,0,0),一条 p { color: blue !important; } 也能覆盖它。
但注意两个关键限制:
-
!important只作用于声明的单个属性,不是整条规则。比如p { color:red !important; font-size:14px; }中只有color被强制,font-size仍走正常权重流程 - 多个
!important同时存在时,才回归权重比较。即#x p { color:green !important; }会赢过.y .z { color:blue !important; },因为(0,1,0,1) > (0,0,2,0) - 内联样式本身不能带
!important(style="color:red !important"无效),这是语法错误
继承样式和通配符 * 的权重是多少
继承来的样式(比如父元素设了 color: gray,子 span 没设但显示灰色)权重是 (0,0,0,0),甚至低于 *(也是 (0,0,0,0))。这意味着只要有一条最低级的规则,比如 span { color: black; }((0,0,0,1)),就能覆盖继承值。
通配符 * 看似“万能”,其实毫无统治力:
-
* { margin: 0; }可被任意元素选择器覆盖,比如div { margin: 10px; } -
* + p这种组合里,*不贡献权重,真正起作用的是p(d=1)和+(0) - 用
*[class]选所有带 class 的元素?它只是属性选择器,权重(0,0,1,0),不是通配符加成
真正容易被忽略的是:当所有规则权重都为 (0,0,0,0)(比如纯继承 + *),浏览器才启用“源顺序”规则——后写的生效。但这在现代项目里极少单独出现,通常意味着样式组织已失控。


















