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" |
| B | ID | #app |
| C | 类、属性、伪类 | .btn、[disabled]、:hover |
| D | 标签、伪元素 | div、h1、::before |
2)典型例子
| 选择器 | 权重 |
|---|---|
p | 0-0-0-1 |
.title | 0-0-1-0 |
.card .title:hover | 0-0-3-0 |
#app .title | 0-1-1-0 |
style="" | 1-0-0-0 |
3)比较方式
不是把 0-1-0-0 算成 100,也不是把 0-0-10-0 算成 10 后去比大小。
正确规则是:
- 先比
A - 再比
B - 再比
C - 最后比
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不是加分,是先换赛道。