跳到主要内容

CSS 权重

面试速答(30 秒版 TL;DR)

  • CSS 权重就是 Specificity,本质是在比较“哪个选择器更具体”。
  • 但面试里一定要先补一句:权重不是第一关,它前面还有来源与重要性@layer 等层叠规则。
  • 常见计算法记成四段:A-B-C-D
    • A:内联样式
    • B:ID 选择器
    • C:类、属性选择器、伪类
    • D:标签、伪元素
  • 比较规则不是加总分,而是从左到右逐列比较;只要前面某一列分出高低,后面就不用比了。

心智模型

权重回答的是这个问题:

多条规则都命中同一个元素的同一个属性时,谁更“具体”?

例如:

.title {
color: #64748b;
}

#app .title {
color: #0f172a;
}

第二条更具体,因为多了一个 #app,所以更容易赢。

但你要强调:

  • 先确保在同一条层叠赛道里再比权重
  • !important、来源差异、@layer 都可能让权重根本没有出场机会

一、权重怎么算

1)四段模型

段位代表内容示例
A内联样式style="color:red"
BID#app
C类、属性、伪类.btn[disabled]:hover
D标签、伪元素divh1::before

2)典型例子

选择器权重
p0-0-0-1
.title0-0-1-0
.card .title:hover0-0-3-0
#app .title0-1-1-0
style=""1-0-0-0

3)比较方式

不是把 0-1-0-0 算成 100,也不是把 0-0-10-0 算成 10 后去比大小。

正确规则是:

  1. 先比 A
  2. 再比 B
  3. 再比 C
  4. 最后比 D

所以:

  • 0-1-0-0 一定赢 0-0-999-999
  • 多个类选择器也打不过一个 ID

二、哪些会加权,哪些不会

会加权

  • ID:#app
  • 类:.card
  • 属性选择器:[type="text"]
  • 伪类::hover:focus:nth-child(2)
  • 标签:div
  • 伪元素:::before

不会加权

  • 通配符:*
  • 组合符:空格、>+~
  • :where() 本身和它的参数

例如下面两个选择器权重一样:

.card .title
.card > .title

因为空格和 > 只是关系说明,不参与计分。


三、现代面试里容易追问的特殊点

1)!important

!important 不是“给权重加分”,而是直接进入更高的重要性赛道。

所以更准确的表述是:

  • 先分 !important 和普通声明
  • 在同一赛道里,才继续比权重和顺序

2):is():not():has()

这几个函数式伪类自身不单独加一层特殊权重,它们的权重取决于参数里最重的那个选择器

例如:

:is(.card, #app) .title

这里 :is(.card, #app) 会按 #app 那条更重的分支参与比较。

3):where()

:where() 很特殊,它的权重始终是 0,常用来写“默认样式但不抢优先级”的基础规则。


四、典型题 & 标准答法

Q1:为什么 .a.b 输给了 #app h2

答法:

  • .a.b 的权重是 0-0-2-0
  • #app h2 的权重是 0-1-0-1
  • 第二列 ID 数量已经分出高低,所以 #app h2

Q2:为什么我把选择器写得更长还是没赢?

答法:

  • 权重不看“字符长度”或“看起来复杂不复杂”
  • 只看内联、ID、类/属性/伪类、标签/伪元素这些计分项
  • 很长的标签链,也打不过一个 ID

Q3:权重一样时怎么办?

答法:

  • 在同一层叠赛道里,权重一样就看书写顺序
  • 后写覆盖先写

常见追问

1)HTML 里类名顺序会影响结果吗?

不会。class="btn primary"class="primary btn" 对权重没有区别。

2)内联样式是不是永远最大?

不是。外部样式中的 !important 可以覆盖内联的普通声明。

3)为什么团队里不推荐堆很多 ID 和超长选择器?

因为虽然“更容易赢”,但维护成本高,后续覆盖会越来越困难,样式系统会失控。


易错点/坑

  • 把权重当成简单加法或十进制总分。
  • 忽略了 !important@layer,直接上来算权重。
  • 误以为空格、>+~ 这些组合符会加权。
  • 误以为 :where() 和普通伪类一样会计分。

速记要点(可背诵)

  • 权重只在同一层叠赛道里比较。
  • 计算法:内联 > ID > 类/属性/伪类 > 标签/伪元素。
  • 逐列比较,不是总分制。
  • !important 不是加分,是先换赛道。