CSS 基础学习系列:CSS 选择器与优先级规则(从入门到能 debug 常见坑)
CSS 选择器是 CSS 的“定位器”,优先级(Specificity)则是决定“谁的样式最终生效”的裁判。本文从最基础讲起,一步步到实际开发中最容易踩的坑。
一、CSS 选择器分类(常用到冷门)
| 分类 | 语法示例 | 权重(Specificity) | 说明与使用场景 |
|---|---|---|---|
| 通配选择器 | * | 0,0,0,0 | 全局重置样式(慎用,性能差) |
| 元素(类型)选择器 | div, p, a | 0,0,0,1 | 基础标签样式 |
| 类选择器 | .btn, .card | 0,0,1,0 | 最常用,复用性强 |
| 属性选择器 | [type="text"], [data-status="error"] | 0,0,1,0 | 表单、自定义属性 |
| 伪类 | :hover, :first-child, :nth-child(2) | 0,0,1,0 | 交互状态、结构位置 |
| ID 选择器 | #header, #main | 0,1,0,0 | 唯一元素(现代开发尽量少用) |
| 内联样式 | <div style="color:red"> | 1,0,0,0 | 最高优先级(除 !important 外) |
| !important | color: red !important; | 超越一切(同属性) | 最高,但尽量避免使用 |
| 伪元素 | ::before, ::after, ::first-letter | 0,0,0,1 | 装饰性元素 |
| 组合/关系选择器 | div > p, .parent .child, li + li | 累加 | 上下文关系 |
| 现代选择器 | :is(), :where(), :has() | 特殊(后面讲) | 降低/控制权重利器 |
二、优先级(Specificity)计算规则 —— 核心重点
现代浏览器使用 四位权重 来计算(从高到低):
a, b, c, d
↑ ↑ ↑ ↑
内联 ID 类/属性/伪类 元素/伪元素
计算规则(最权威的 MDN 标准):
- d(千位):内联样式(style 属性) → 1
- a(百位):ID 选择器个数 → 每个 #id +1
- b(十位):类、属性、伪类个数 → 每个 .class / [attr] / :hover +1
- c(个位):元素、伪元素个数 → 每个 div / p / ::before +1
比较规则:从左到右逐位比较,第一位不同就分胜负,绝不进位!
常见例子计算:
| 选择器 | a (ID) | b (类/属性/伪类) | c (元素) | 权重写法 | 解释 |
|---|---|---|---|---|---|
* | 0 | 0 | 0 | 0,0,0,0 | 通配 |
p | 0 | 0 | 1 | 0,0,0,1 | 元素 |
.btn | 0 | 1 | 0 | 0,0,1,0 | 类 |
div.btn | 0 | 1 | 1 | 0,0,1,1 | 类 + 元素 |
#header .logo | 1 | 1 | 0 | 0,1,1,0 | ID + 类 |
#header #logo | 2 | 0 | 0 | 0,2,0,0 | 两个 ID(不推荐) |
ul > li.active:hover | 0 | 2 | 2 | 0,0,2,2 | 伪类 + 类 + 两个元素 |
<div style="color:red"> | — | — | — | 1,0,0,0 | 内联(最高,除 !important) |
color: blue !important | — | — | — | 超越一切 | 仅同属性内最高 |
经典面试/实战对比题:
/* 权重:0,0,0,1 */
p { color: red; }
/* 权重:0,0,1,0 */
.intro { color: blue; }
/* 权重:0,0,1,1 */
p.intro { color: green; }
/* 权重:0,1,0,0 */
#special { color: orange; }
<p class="intro" id="special">文字颜色是?</p>
答案顺序(从高到低):
#special→ orange(ID 最高)p.intro→ green(类+元素).intro→ blue(类)p→ red(元素)
三、!important 的真相
- !important 只在同属性上比较,且优先级高于一切(包括内联样式)
- 同 !important 情况下,再看普通 specificity
- 不带 !important 的规则永远输给带 !important 的规则(同属性)
建议:能不用就不用,用了之后后期维护会非常痛苦。
四、现代 CSS 控制权重的神器(推荐学习)
:is()→ 内部最高权重决定整个 :is() 的权重
:is(#header, .main) .title { ... } /* 权重取决于 #header 或 .main 哪个被匹配 */
:where()→ 永远 0,0,0,0 权重(非常适合组件库/基础样式)
:where(.card) .title { color: #333; } /* 权重 0,0,0,0,可被 .title 轻松覆盖 */
:has()→ 父选择器(权重 = 内部选择器权重)
五、优先级之外的层叠规则(Cascade)
当 specificity 相同时,遵循以下顺序(从高到低):
- Transition 中的声明(动画中)
- !important 用户代理(浏览器默认)
- !important 用户样式表
- !important 作者样式表
- 动画(animation)
- 作者样式表(我们写的)
- 用户样式表
- 浏览器默认
最常见规则:源码中后出现的相同权重规则覆盖前面的。
六、实用建议(防坑指南)
- 尽量使用类选择器,少用 ID(ID 权重太高,难覆盖)
- 避免 !important(除非 reset 或第三方库覆盖)
- 不要过度嵌套(增加无谓权重)
- 组件化开发 → 推荐 BEM / CSS Modules / Scoped(基本解决权重冲突)
- 调试技巧:浏览器开发者工具 → Computed → 看到所有规则 + 划掉的规则,能直观看到谁赢了
- 现代项目 → 多用
:where()和:is()降低基础样式权重
小练习(自己算一算)
A: #sidebar .widget-title { color: navy; }
B: .sidebar-title { color: purple; }
C: div #sidebar h3.title { color: maroon; }
D: h3 { color: teal !important; }
<div id="sidebar">
<h3 class="widget-title sidebar-title title">标题颜色是?</h3>
</div>
答案:D → teal(因为 !important 最高)
有任何选择器或优先级冲突的实际代码想分析,欢迎贴出来,我帮你算权重和解释为什么!