CSS 的入门痛点不是语法(语法简单到近乎简陋),而是「为什么我写的样式没生效」。答案永远在 CSS 的两套裁决规则里:层叠(谁赢)和继承(谁传下来)。本章把这些机制拆开讲透,顺带把选择器和盒模型这两个地基打好。学完本章的目标:面对「样式不生效」,你能在 DevTools 里 30 秒内定位原因,而不是盲目加 !important。
<p style="color:red">行内样式:写死在标签上</p>
<style> p { color: green } </style> <!-- 内部样式:页内 -->
<link rel="stylesheet" href="style.css" /> <!-- 外部样式:生产首选 -->
外部样式是工程首选,理由都和浏览器缓存有关:所有页面共享一份 CSS 文件,下载一次全站复用(计网课第 2 章的 HTTP 缓存),HTML 只留结构。行内样式权重最高但不可复用、难维护,只留给 JS 动态改样式的场景(第 4 章)。
#app { } /* ID:唯一 */
.box { } /* 类:可复用,日常主力 */
p { } /* 元素:全局影响,慎用 */
input[type="text"] { } /* 属性 */
a:hover { } /* 伪类:状态 */
li:nth-child(2n) { } /* 结构伪类:偶数行,斑马纹一秒写好 */
p::before { } /* 伪元素:凭空造节点 */
.nav a { } /* 后代:任意深度的 a */
.nav > li { } /* 子代:只有直接子级 */
两个易混点。后代(空格)vs 子代(>):.nav a 会命中 nav 里任何深度的 a(包括嵌套组件里的),.nav > li 只命中直接子级;写组件样式时用子代能避免「样式泄漏进嵌套的组件」。伪类 vs 伪元素:伪类选「状态的元素」(:hover 悬停、:focus 聚焦、:first-child),伪元素造「不存在的节点」(::before/::after 可以不写 HTML 就加装饰,前缀小图标、清除浮动的老朋友)。
工程风格建议:类选择器为主、组合要短(.card .title 两层封顶)、ID 选择器尽量不用(权重太高,后面想覆盖都难,2.5 见)。
每个元素都是一个盒子,从内到外四层:
┌ margin(外边距:推挤邻居)
│ ┌ border(边框)
│ │ ┌ padding(内边距:内容与边框之间)
│ │ │ ┌ content(内容)
坑在 width 的定义。默认(content-box)下 width 只算内容,加了 padding 和 border,盒子总宽悄悄变大:
.box { width: 100px; padding: 10px; border: 2px solid; }
/* content-box:实际占 100 + 20 + 4 = 124px,布局对不齐的元凶 */
* { box-sizing: border-box; } /* 行业惯例:width = 总宽,内容自动让位 */
border-box 让「设 100px 就是 100px」,心智负担骤降,所以现代项目(包括 Tailwind)全局重置为 border-box,这也是你该写进每个项目 reset 的第一行。margin 的特殊行为也值得点名:垂直 margin 会合并(相邻元素的上下 margin 取大者而非相加),以及margin 不算进元素自身尺寸,这两个行为在调试间距时最容易让人怀疑人生。
继承:部分属性从父元素自动传给后代——文字类的(color、font 系列、line-height)继承,盒子类的(margin、padding、border、width)不继承。直觉:继承「文风」合理(整段颜色统一),继承「边框」就是灾难(每个后代都描边)。不知道某属性继不继承时,DevTools 的 Computed 面板里每个属性都标注了 inherited 状态,查它。
层叠:多个规则命中同一元素的同一属性时,按固定顺序裁决:来源(浏览器默认、用户、作者依次升级)→ 优先级 → 书写顺序(后者赢)。
权重按 (ID 数, 类/伪类/属性数, 元素数) 三元组从左到右比较:
| 选择器 | 权重 |
|---|---|
p | (0,0,1) |
.nav a:hover | (0,2,1) |
#app .box | (1,1,0) |
| 内联 style | 碾压全部 |
!important | 碾压一切常规(别用,除非覆盖第三方库) |
实操推论:为什么「少用 ID 选择器」?因为一个 ID 的权重(1,0,0)高于任何数量的类,你写十个类也盖不过它,覆盖只能上 !important,然后恶性循环。调试「为什么没生效」的固定动作:DevTools 选中元素 → Styles 面板看这条规则在不在 → 在但被划掉,说明被更高权重覆盖(划掉它的规则就在上面);不在,说明选择器根本没选中(回去查层级)。
.nav a 命中所有深度的链接;组件化时代用 .nav > a 或给链接起类名。p、.box、#app、内联四种规则上色,在 DevTools Styles 面板观察划线覆盖关系,抄录优先级裁决的实际顺序。