浏览器按选择器权重(a,b,c,d)规则决定样式生效,而非书写顺序;a为内联样式数,b为id数,c为类/属性/伪类数,d为标签/伪元素数,逐位比较如版本号。

怎么快速算出哪个CSS选择器会生效
浏览器不是靠“谁写在后面”决定样式的,而是按一套权重规则硬算出来的。你得把选择器拆成四类数字(a,b,c,d),按从左到右顺序比大小——就像比较版本号 v1.2.3.4 那样。
实操时别手算,直接套公式:a:内联样式(style="...")计 1,否则 0b:ID 选择器个数(#header、div#main 都算 1 个)c:类名、属性、伪类个数(.btn、[type="submit"]、:hover 各算 1)d:标签名、伪元素个数(div、p::before 各算 1)
-
#nav .item:hover→ a=0, b=1, c=2(.item+:hover), d=1(div?不,这里没标签名!等等——它前面没标签,所以 d=0)→ 实际是0,1,2,0 -
div#nav ul li.active a→ a=0, b=1(只有#nav), c=1(.active), d=4(div、ul、li、a)→0,1,1,4 - 注意:
!important不参与权重计算,它是在权重相等后才“插队”的,且只对单个声明有效
为什么 .class1.class2 比 div.class1 权重高
因为权重看的是“数量”,不是“长度”或“看起来多高级”。两个类名 = c=2;一个标签+一个类 = c=1, d=1 → 对应 0,0,2,0 vs 0,0,1,1。前者 c 位更大,直接胜出,d 再大也没用。
- 连续写多个类(
.a.b.c)就是纯堆 c 值,非常高效 - 用标签限定(
button.primary)反而拉低竞争力,除非你真需要它只作用于button - 后代选择器(
.parent .child)里每个部分单独算,但整体权重是各部分之和——.parent是 c=1,.child是 c=1,合起来 c=2
遇到 !important 别急着加,先查权重是否真被压了
很多人一看到样式不生效就狂加 !important,结果埋下维护雷:后续想覆盖它,只能用更暴力的 !important 或内联样式。其实 80% 的场景,只是你没意识到某个父级规则权重更高。
立即学习“前端免费学习笔记(深入)”;
- 打开 Chrome DevTools → 选中元素 → 看 Styles 面板里被划掉的声明,鼠标悬停会显示「specificity」值,点开还能看到是哪个规则赢了
-
* { color: red !important }这种全局写法,会让所有其他颜色声明失效,连内联样式都拦不住 - 如果必须用
!important,优先加在低权重选择器上(比如.btn { color: blue !important }),而不是去怼高权重的老代码
伪类和伪元素权重容易搞混
:hover、:nth-child()、:not() 都算伪类,计入 c;而 ::before、::placeholder 是伪元素,计入 d。这个区分直接影响结果。
-
a:hover→ c=1(:hover), d=1(a)→0,0,1,1 -
a::before→ c=0, d=2(a+::before)→0,0,0,2,比上面那个还低 -
:not(.disabled)整体算 1 个伪类(c +=1),括号里.disabled不额外加分 —— 它只是:not()的参数,不是独立选择器 - 别信“
:is()会降权”这种传言,:is(.a, .b, .c)就按里面最高权重的那个算(比如三个都是类,c=1)
权重不是玄学,但它的“进位规则”很反直觉:c=11 不敌 b=1,哪怕 b 只是 1 个 ID。真正卡住人的,往往是漏算了某个隐含的类、伪类,或者误把伪元素当伪类。动手前,先拆解再对位,比反复刷新页面有效得多。








