第 29 节 · 层叠、继承与优先级全解
第 29 节 · 层叠、继承与优先级全解
📌 版本信息:基于 CSS Cascading and Inheritance Level 5(现行规范;2026-08-29 核对) 📚 来源:MDN 层叠 | CSS Specificity 完整算法
一、这一节的目标
- 背下优先级计分的完整算法(三位数)
- 理解层叠的完整裁决顺序:来源与重要性 → 层 → 优先级 → 顺序
- 掌握继承:哪些属性会传给子孙、怎么控制
!important为什么是禁手、什么情况是唯一解- 拥有"读到任意一条 CSS 就知道它赢不赢"的判断力
二、优先级计分:三位数算法
每条选择器算一个三位数(A-B-C),高位大者胜:
| 位 | 计什么 | 每个计 1 分 |
|---|---|---|
| A(百位) | ID 选择器 | #app |
| B(十位) | 类选择器、伪类、属性选择器 | .card、:hover、[type="text"] |
| C(个位) | 元素选择器、伪元素 | p、::before |
* {} /* 0-0-0 */
p {} /* 0-0-1 */
p:hover {} /* 0-1-1 */
.card p {} /* 0-1-1(同分,看书写顺序) */
#app .map .btn {} /* 1-2-0 */
style="…"(行内) /* 视为 1-0-0-0(更高一位) */
!important /* 打破一切(最后一节细说) */
三个必懂细节:
- 通配符
*、组合符(>、空格)不记分——.card > p还是 0-1-1 - 同级比较看源码顺序:后写的赢
- 优先级是"整条选择器"的合计,不是"最狠的那段":
#app .card是 1-1-0
💡 直觉训练:看到
#sidebar ul li a:hover(1-1-3)你能立刻报分——这种判断力在排查"样式不生效"时是超能力。
三、层叠的完整裁决顺序
同一条声明冲突时,浏览器按下面顺序裁决(越往下越强):
1. 来源与重要性:
浏览器默认样式 < 用户样式 < 开发者样式
(每层内部又分普通 / !important,!important 反转顺序)
2. @layer 层级(v4 Tailwind 的底层机制之一)
3. 优先级(A-B-C 计分)
4. 源码顺序(后者胜)
实战结论:日常 95% 的冲突在第 3、4 步就分出胜负——你只需要算分 + 知道顺序。剩下 5%(第三方库覆盖)才需要 !important 或更高优先级选择器。
四、继承:哪些属性会"传家"
默认继承的(文字类):color、font-*(family/size/weight)、line-height、text-align、letter-spacing、visibility。
默认不继承的(盒子类):width、height、margin、padding、border、background。
body { color: #333; font: 14px/1.6 sans-serif; }
/* 全页文字自动继承这两条——这就是"在 body 上设全局字体"的原理 */
/* 三个继承控制关键字 */
color: inherit; /* 强制继承父亲 */
color: initial; /* 回到规范初始值(黑) */
color: unset; /* 有继承就继承,没有就初始(聪明但少用) */
💡 为什么按钮里的字不信 body 的字体?——浏览器给
button/input的默认样式带了自己的 font,覆盖了继承。老项目的"reset 样式"主要就是在修这些浏览器默认值(Tailwind 的 preflight 也干这个)。
五、!important:最后手段
/* 反转层叠:带 important 的普通声明 > 别人的 important > 所有普通声明 */
.card { color: red !important; }
为什么是禁手:它不参与计分、只能靠另一条 important 反制——用三个以后整个项目的优先级体系报废,后来者只能加更多 important("important 军备竞赛")。
合法场景(几乎全部是"覆盖第三方/浏览器固执样式"):
- 覆盖第三方库的行内样式(它 style="…" 你没法提高选择器)
- 无障碍用户样式表
- 全局兜底(如
.hidden { display: none !important }——Tailwind 就是这么定义 hidden 的)
六、实战方法论:样式不生效的排查树
样式没生效?
├─ 1. 选择器选中它了吗?→ DevTools Elements 里看该元素
│ (没有任何命中 → 选择器写错/结构变了)
├─ 2. 命中了但被划线(删除线)?→ 被更高优先级覆盖
│ → 看是哪条赢的,算一算双方分值
├─ 3. 赢的来自哪?→ Sources 面板看文件,第三方库就用更高优先级或 important
└─ 4. 还不对?→ 检查拼写、选择器是否需要 > 加深、是否被层/顺序反转
七、自测题
- 报出
#app .nav li a.active的优先级三数。 - 同为 0-1-1 的两条规则,谁赢?
border会继承吗?font-size呢?- 为什么
<button>里的字不受 body 字体影响? - 覆盖第三方库行内样式,除了
!important还有招吗?
参考答案
- 1-2-2(1 个 ID、2 个类、2 个元素——
.nav和.active是类,lia是元素)。 - 源码顺序靠后的赢。
- border 不继承;font-size 继承。
- 浏览器默认样式给表单控件自带 font,声明比继承优先。
- 行内样式只能用
!important对抗(行内 > 一切选择器,important 才能跨过行内);或改库源码/配置项。
八、下一步
规则懂了 → 第 30 节:CSS 单位与变量,尺寸世界全解析 + 自定义属性(Tailwind v4 主题的底层)。