5月28日 03:23

CSS 选择器的权重怎么计算?

CSS 权重(Specificity)用四元组 (a, b, c, d) 表示,从左往右逐位比较,高位相同才比下一位:

位置含义示例每个贡献值
a行内样式style=""1
bID 选择器#header+1
c类/属性/伪类.nav、[type="text"]、:hover+1
d标签/伪元素div、::before+1

:::tip 通配符 * 、组合符(>、+、~、空格)不贡献权重。 :where() 始终零权重, :is() 取参数中最高权重参与计算。 :::

权重计算实战

逐个拆解选择器,把各部分归入对应位:

css
/* (0, 1, 0, 0) */ #header { } /* (0, 0, 2, 1) — 2个类 + 1个标签 */ .nav .item a { } /* (0, 1, 1, 0) — 1个ID + 1个类 */ #sidebar .active { } /* (0, 0, 1, 2) — 1个伪类 + 2个标签 */ div p:hover { } /* (0, 0, 0, 0) — 通配符不贡献 */ * { }

比较规则:高位相同才比下一位(0,1,0,0) 永远大于 (0,0,99,99) ——ID 列永远比 class 列大,不可进位。

!important 与权重的关系

!important 不参与四元组计算,它独立于权重体系之外:

shell
优先级从高到低:!important > 行内 > ID > class > tag > *

当多条 !important 规则冲突时,回到权重比较决定谁胜出;权重也相同则后写的覆盖先写的。

css
.box { color: red !important; } /* 同为 !important,回到权重比较 */ #box { color: blue !important; } /* #box 权重更高,blue 胜出 */

:::warning 滥用 !important 会导致样式不可维护,只能在覆盖第三方库等少数场景使用,并注释原因。 :::

:is() 与 :where() 的权重差异

这是面试高频追问点:

css
/* :is() 取参数最高权重 */ :is(.nav, #main) a { } /* 等价于 #main a → (0, 1, 0, 1) */ /* :where() 始终零权重 */ :where(.nav, #main) a { } /* 等价于 a → (0, 0, 0, 1) */

:where() 的零权重特性非常适合写基础/重置样式——使用者用任意 class 即可覆盖,无需担心权重冲突。

@layer 对权重的影响

CSS Cascading Layers(@layer)引入了层叠层的概念,层的优先级规则:

  • 无层样式 > 具名层样式(不管权重多高)
  • 层内按声明顺序:后声明的层优先级更高
  • 同一层内才按权重比较
css
@layer base { #header { color: blue; } /* (0,1,0,0) 但在 base 层 */ } /* 无层 —— 即使权重低也会赢 */ .header { color: red; } /* (0,0,1,0) 无层,优先级更高 */

继承的权重

继承的样式没有权重,甚至低于通配符 *

css
* { color: gray; } /* (0,0,0,0) 但属于直接匹配 */ body { color: black; } /* 子元素通过继承得到 black */ /* p 元素会显示 gray —— 直接匹配 > 继承 */

实际项目中的权重管理策略

  1. BEM 命名:只用 class,杜绝 ID 和嵌套选择器,权重始终为 (0,0,1,0) 级别
  2. 选择器嵌套不超过 3 层.block__element--modifier 足够,避免 .a .b .c .d
  3. 用 :where() 写重置样式where(reset) 可被任意 class 轻松覆盖
  4. CSS Modules / Scoped CSS:工具自动处理作用域,天然避免权重冲突
  5. 避免 !important:仅在覆盖第三方库样式时使用,务必注释原因

追问

多个类选择器和一个 ID 选择器哪个权重高?

ID 权重更高。#foo(0,1,0,0).a.b.c.d.e 再多类也是 (0,0,5,0)——高位相同才比下一位,b 列 1 > c 列 5,ID 永远胜出。

怎么快速判断两个选择器的优先级?

分三步:(1) 先看有没有 !important;(2) 再看是否在 @layer 中(无层 > 有层);(3) 最后按四元组从左往右逐位比。同权重时后写的覆盖先写的。

内联样式和 !important 谁优先?

!important 优先。!important > 行内样式 > ID > class > tag。但两条都是 !important 时,再回到权重体系比较。

伪类 :not() 的权重怎么算?

:not() 本身不贡献权重,但它括号内的选择器参与计算。:not(.foo) 的权重等于 .foo,即 (0,0,1,0)。同理 :not(#bar) 按 ID 计算权重 (0,1,0,0)。注意 :not() 内可以写复杂选择器,取其完整权重。

标签:CSS