伪类选择器权重与类选择器相同,均为0,0,1,0;:hover、:nth-child()等不因动态性升权或降权,而是统一计入[b]位;复合伪类:is()取内部最大权重,:where()权重为0。

伪类选择器的权重不是“额外加分”,而是计入类选择器那一档
很多人以为 :hover、:nth-child()、:not() 是“特殊功能”,所以该有独立权重。其实不是——它们和 .class 一样,都属于「类/属性/伪类」类别,统一按 0,0,1,0 计入权重。比如:
-
a:hover→ 0个 ID + 1个伪类 + 1个元素 =0,0,1,1 -
.nav a:hover→ 0个 ID + 2个伪类/类(.nav和:hover)+ 1个元素 =0,0,2,1 -
#menu .nav a:hover→ 1个 ID + 2个伪类/类 + 1个元素 =0,1,2,1
关键点在于:伪类不因“动态”或“条件性”而降权,也不因“看起来复杂”而升权。它只是规则的一部分,和其他类选择器平起平坐。
:nth-child(n) 和 :nth-of-type(n) 的权重相同,但匹配逻辑完全不同
这两个伪类权重都是 0,0,1,0(只算伪类本身,不看括号里内容),但浏览器匹配时根本不在同一维度上:
-
p:nth-child(2)检查的是「父元素下第 2 个子节点是否是p」 -
p:nth-of-type(2)检查的是「父元素下第 2 个p元素」
所以即使权重一样,一条规则可能根本没匹配到元素,另一条却生效了——这不是优先级问题,是选择器语义失效。调试时别急着调权重,先用 DevTools 的「Computed」面板确认该规则是否命中目标元素。
立即学习“前端免费学习笔记(深入)”;
复合伪类如 :is()、:where() 会改变权重计算方式
现代 CSS 中,:is() 和 :where() 内部的选择器权重取最大值,但处理方式不同:
-
:is(.btn, #primary a)权重 = max(0,0,1,0,0,1,0,1) =0,1,0,1 -
:where(.btn, #primary a)权重 =0,0,0,0(完全忽略内部所有选择器权重)
这意味着::where() 是“零权重透传”,适合写通用重置;而 :is() 可能意外拉高整条规则权重,导致覆盖其他本不该被覆盖的样式。用之前务必在 DevTools 的 Styles 面板里点开规则,看右上角显示的 specificity 值。
伪类顺序不影响权重,但影响可读性和维护性
a:hover:focus 和 a:focus:hover 权重完全一样(都是 0,0,2,1),浏览器也等价处理。但实际中:
- 用户通常先 hover 再 focus,
:hover:focus更贴近行为流 - 某些辅助技术对 focus 状态更敏感,
:focus:hover可能造成焦点丢失后样式残留 - 多人协作时,固定书写顺序(如按 DOM 事件流:
:hover→:active→:focus)能减少歧义
真正容易被忽略的是:伪类组合一旦嵌套过深(比如 div > ul li:first-child a:not([disabled]):hover),虽然权重只到 0,0,3,4,但可维护性已崩坏——这时候该想的不是“怎么赢过别人”,而是“能不能拆成独立 class”。


















