前端阅读 655月28日 03:23
CSS 选择器的权重怎么计算?
CSS 权重(Specificity)用四元组 (a, b, c, d) 表示,从左往右逐位比较,高位相同才比下一位:| 位置 | 含义 | 示例 | 每个贡献值 ||------|------|------|-----------|| a | 行内样式 | style="" | 1 || b | ID 选择器 | #header | +1 || c | 类/属性/伪类 | .nav、[type="text"]、:hover | +1 || d | 标签/伪元素 | div、::before | +1 |:::tip通配符 * 、组合符(>、+、~、空格)不贡献权重。 :where() 始终零权重, :is() 取参数中最高权重参与计算。:::权重计算实战逐个拆解选择器,把各部分归入对应位:/* (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 不参与四元组计算,它独立于权重体系之外:优先级从高到低:!important > 行内 > ID > class > tag > *当多条 !important 规则冲突时,回到权重比较决定谁胜出;权重也相同则后写的覆盖先写的。.box { color: red !important; } /* 同为 !important,回到权重比较 */#box { color: blue !important; } /* #box 权重更高,blue 胜出 */:::warning滥用 !important 会导致样式不可维护,只能在覆盖第三方库等少数场景使用,并注释原因。::::is() 与 :where() 的权重差异这是面试高频追问点:/* :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)引入了层叠层的概念,层的优先级规则:无层样式 > 具名层样式(不管权重多高)层内按声明顺序:后声明的层优先级更高同一层内才按权重比较@layer base { #header { color: blue; } /* (0,1,0,0) 但在 base 层 */}/* 无层 —— 即使权重低也会赢 */.header { color: red; } /* (0,0,1,0) 无层,优先级更高 */继承的权重继承的样式没有权重,甚至低于通配符 *:* { color: gray; } /* (0,0,0,0) 但属于直接匹配 */body { color: black; } /* 子元素通过继承得到 black *//* p 元素会显示 gray —— 直接匹配 > 继承 */实际项目中的权重管理策略BEM 命名:只用 class,杜绝 ID 和嵌套选择器,权重始终为 (0,0,1,0) 级别选择器嵌套不超过 3 层:.block__element--modifier 足够,避免 .a .b .c .d用 :where() 写重置样式:where(reset) 可被任意 class 轻松覆盖CSS Modules / Scoped CSS:工具自动处理作用域,天然避免权重冲突避免 !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() 内可以写复杂选择器,取其完整权重。