CSS 选择器、层叠与继承深度解析

2024-08-26 前端

CSS(Cascading Style Sheets)是前端开发的核心技术之一。要写出可维护、高性能的样式,就必须深刻理解三个关键概念:选择器(Selectors)、层叠(Cascade) 与 继承(Inheritance)。本文将从零开始,系统性地深入每一个细节,配合大量可运行的代码示例,帮助你彻底掌握 CSS 的核心机制。


一、CSS 选择器大全

CSS 选择器用于定位 HTML 文档中的元素并对其应用样式。按照复杂度,我们可以将它们分为六大类。

1.1 基本选择器

基本选择器是 CSS 的基石,包括四种:

类型 语法 示例 说明
元素选择器 element div {} 选中所有 <div> 元素
类选择器 .class .highlight {} 选中所有 class="highlight" 的元素
ID 选择器 #id #header {} 选中 id="header" 的唯一元素
通配符选择器 * * {} 选中页面中所有元素

示例代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <style>
    /* 元素选择器 */
    p { color: #333; font-size: 16px; }

    /* 类选择器 */
    .warning { color: #d9534f; font-weight: bold; }

    /* ID 选择器 — 每个页面应该只使用一次 */
    #app { max-width: 1200px; margin: 0 auto; }

    /* 通配符 — 全局重置(性能开销大,慎用) */
    * { box-sizing: border-box; }
  </style>
</head>
<body>
  <div id="app">
    <p>这是普通段落。</p>
    <p class="warning">这是警告内容!</p>
  </div>
</body>
</html>

最佳实践:ID 选择器特异性很高且不可复用,应优先使用类选择器。通配符 * 会遍历所有元素,在大型页面中应避免高频使用。


1.2 组合器(Combinators)

组合器定义了选择器之间的关系。

组合器 符号 语义 示例
后代组合器 (空格) 选中的后代元素(所有层级) div p
子代组合器 > 选中的直接子元素(仅第一层) div > p
相邻兄弟组合器 + 紧跟在第一个元素后的兄弟元素 h2 + p
后续兄弟组合器 ~ 第一个元素之后的所有兄弟元素 h2 ~ p

示例代码:

注意:组合器可以串联使用,例如 nav ul > li.active + li 表示:nav 内部的 ul 的直接子元素 li.active 之后的第一个 li。


1.3 属性选择器

属性选择器允许根据 HTML 属性的存在或值来匹配元素,是 CSS 中最强大的定位工具之一。

语法大全

模式 含义
[attr] 存在 attr 属性即可
[attr="val"] 属性值 完全等于 val
[attr^="val"] 属性值 以 val 开头
[attr$="val"] 属性值 以 val 结尾
[attr*="val"] 属性值 包含 val 子串
[attr~="val"] 属性值是用空格分隔的词列表,其中一个是 val
[attr|="val"] 属性值等于 val 或以 val- 开头
[attr="val" i] 加上 i 标志则不区分大小写

真实场景示例

实用技巧:属性选择器与 data-* 自定义属性配合使用,可以在不新增类名的情况下实现状态驱动的样式。


1.4 伪类(Pseudo-classes)

伪类以 : 开头,描述元素的特殊状态。它们是 CSS 中最庞大也最强大的选择器家族。

1.4.1 结构性伪类

结构性伪类基于元素在 DOM 树中的位置进行选择。

伪类 说明
:first-child 父元素的第一个子元素
:last-child 父元素的最后一个子元素
:first-of-type 兄弟元素中该类型的第一个
:last-of-type 兄弟元素中该类型的最后一个
:nth-child(n) 父元素的第 n 个子元素
:nth-last-child(n) 父元素中从后往前第 n 个子元素
:nth-of-type(n) 兄弟元素中该类型的第 n 个
:nth-last-of-type(n) 兄弟元素中该类型的倒数第 n 个
:only-child 父元素唯一的子元素
:only-of-type 兄弟元素中该类型的唯一元素
:empty 没有子元素(包括文本节点)的元素
:not(selector) 不匹配给定选择器的元素
:has(selector) 包含匹配选择器的后代元素的父元素(CSS 选择器第 4 级)

:nth-child() 参数详解:

参数可以是:

  • 数字:2 表示第 2 个
  • 关键字:odd(奇数)、even(偶数)
  • 公式:an + b,如 2n+1(奇数)、3n(每 3 个一组中的第 3 个)、n+4(从第 4 个开始的所有)

1.4.2 用户行为伪类

这些伪类响应用户的交互操作。

伪类 触发条件
:hover 鼠标悬停(触摸设备需谨慎)
:active 元素被激活(如点击按下瞬间)
:focus 元素获得焦点(键盘 Tab 或点击)
:focus-visible 浏览器认为焦点应当可见(键盘导航最佳)
:focus-within 元素自身或其后代获得焦点
:target 元素 ID 匹配 URL 中的片段标识符

重要提醒:focus-visible 是 focus 的现代替代方案——它在鼠标点击时不显示轮廓(避免难看的蓝框),但在键盘 Tab 导航时显示清晰的焦点指示器(无障碍刚需)。这比笼统使用 :focus { outline: none } 更安全。

1.4.3 表单伪类

专门用于表单控件的状态选择。

伪类 匹配条件
:checked 被选中的 checkbox 或 radio
:indeterminate 不确定状态的 checkbox 或 radio
:disabled 被禁用的表单元素
:enabled 可用的表单元素
:required 设置了 required 属性的元素
:optional 未设置 required 属性的元素
:valid 通过约束验证的元素
:invalid 未通过约束验证的元素
:in-range 值在 min/max 范围内的输入
:out-of-range 值超出 min/max 范围的输入
:placeholder-shown 占位文本正在显示的元素
:read-only 只读表单元素
:read-write 可编辑表单元素
:default 一组元素中的默认元素

1.4.4 语言伪类

伪类 说明
:lang(language) 匹配设置了特定语言的元素(基于 lang 属性)
:dir(direction) 匹配特定文字方向的元素(ltr 或 rtl)
/* 中文内容使用特定字体 */
:lang(zh-CN) {
  font-family: "Noto Sans SC", "Microsoft YaHei", sans-serif;
}

/* 阿拉伯语从右到左调整 */
:dir(rtl) {
  text-align: right;
}

/* 不同语言引用样式不同 */
blockquote:lang(en) {
  border-left: 3px solid #007bff;
}
blockquote:lang(zh-CN) {
  border-left: 3px solid #dc3545;
}

1.4.5 其他重要伪类

伪类 说明
:root 文档根元素,相当于 html,但特异性更高
:fullscreen 处于全屏模式的元素
:is(selector_list) 匹配选择器列表中的任意一个(容错:单个失效不影响整体)
:where(selector_list) 与 :is() 功能相同,但特异性始终为 0
:defined 匹配已定义的自定义元素

:is() 与 :where() 的特异性差异:

/* 传统写法 — 需重复写 section */
section h1, section h2, section h3 { color: #333; }

/* :is() 简化 — 但特异性取列表中最高项 */
:is(section, article, aside) h1 { color: #333; }
/* 等同于 section h1, article h1, aside h1 */
/* 特异性 = 元素选择器(0,0,1) + ID选择器(假设列表中最高) */

/* :where() — 特异性始终为零 */
:where(section, article, aside) h1 { color: #333; }
/* h1 的特异性 = (0,0,1),不受 :where() 内部影响 */
/* 因此任何更具体的选择器都能覆盖它 */
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <style>
    /* 使用 :root 定义全局 CSS 变量 */
    :root {
      --primary: #007bff;
      --danger: #dc3545;
      --spacing: 1rem;
    }

    /* :is() 简化分组 */
    :is(h1, h2, h3, h4).section-title {
      border-bottom: 2px solid var(--primary);
    }

    /* :where() 零特异性,方便覆盖 */
    :where(nav, header, footer) a {
      text-decoration: none;
    }
    /* 后续用 .nav-link { text-decoration: underline; } 轻松覆盖 */
  </style>
</head>
<body>
  <h1 class="section-title">主要标题</h1>
  <h2 class="section-title">二级标题</h2>
</body>
</html>

1.5 伪元素(Pseudo-elements)

伪元素以 :: 开头,用于创建或选取元素的特定部分。它们是虚拟的 DOM 节点。

伪元素 说明
::before 在元素内容前插入虚拟子元素(需 content)
::after 在元素内容后插入虚拟子元素(需 content)
::first-letter 块级元素的第一行第一个字符
::first-line 块级元素的第一行文本
::selection 用户选中的文本
::placeholder 表单输入框的占位文本
::marker 列表项的标记(如 bullet 或数字)
::backdrop 全屏元素或对话框后的背景层
::file-selector-button 文件上传控件的按钮部分
::cue WebVTT 字幕
::slotted() 插槽内容(Shadow DOM)

实战示例代码:

关键规则:::before 和 ::after 生成的元素默认是内联元素,且必须设置 content 属性(可以是空字符串 "")。它们在 DOM 中不可见,只存在于 CSS 渲染树中。


1.6 选择器组合使用示例

实际开发中,选择器很少单独使用。让我们看一些真实场景的组合示例。

场景 1:表单验证视觉反馈

/* 必填且无效的输入 */
input:required:invalid {
  border: 2px solid #dc3545;
  background: #fff5f5;
}

/* 必填且有效,且非空(非 placeholder 状态) */
input:required:valid:not(:placeholder-shown) {
  border: 2px solid #28a745;
  background: #f0fff4;
}

场景 2:卡片组件中的各种状态

/* 被聚焦或包含 .active 子元素的卡片 */
.card:focus-within,
.card:has(.active) {
  box-shadow: 0 0 0 3px rgba(0,123,255,0.3);
}

/* 列表中的最后一项且不是唯一一项 */
li:last-child:not(:only-child) {
  border-bottom: none;
}

/* 第 3 个之后且不是最后一个 */
li:nth-child(n+4):not(:last-child) {
  opacity: 0.8;
}

场景 3:响应式导航菜单

/* 当前页面的导航项 — 通过 body 类控制 */
body.page-home .nav-home,
body.page-about .nav-about {
  font-weight: bold;
  border-bottom: 2px solid #007bff;
}

/* 鼠标悬停或焦点时,并且不是当前页面 */
.nav-item:hover:not(.nav-active),
.nav-item:focus-visible:not(.nav-active) {
  color: #007bff;
}

二、层叠(Cascade)

"层叠"(Cascade)是 CSS 名称的由来,也是 CSS 最核心的冲突解决机制。当多个规则同时应用于同一个元素时,层叠决定了哪个规则最终生效。

2.1 层叠优先级总排序

CSS 层叠按以下递增优先级排序(后面的覆盖前面的):

浏览器默认样式
  ↓
用户声明样式(用户浏览器设置)
  ↓
作者普通声明样式(开发者写的 CSS)
  ↓
CSS 动画(@keyframes)
  ↓
作者 !important 声明
  ↓
用户 !important 声明
  ↓
过渡(transition)

但请注意: 实际排序规则更加精细,现代 CSS 的完整层叠排序(从低到高)为:

  1. Normal 层:浏览器样式 → 用户样式 → 作者样式
  2. Animation 层
  3. Important 层:作者 !important → 用户 !important
  4. Transition 层
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <style>
    /* 作者普通声明 */
    p { color: blue; }

    /* 动画中的颜色 — 比普通声明优先级高 */
    @keyframes color-shift {
      from { color: red; }
      to   { color: green; }
    }
    p.animated {
      animation: color-shift 2s infinite;
    }

    /* !important — 最高优先级之一 */
    p { color: black !important; }
    /* 但 transition 比 !important 更高 */
  </style>
</head>
<body>
  <!-- 浏览器默认: 黑色(已被覆盖) -->
  <!-- 作者普通: 蓝色(已被动画覆盖) -->
  <!-- 动画: 红/绿(已被 !important 覆盖) -->
  <!-- !important: 黑色(生效) -->
  <p>这是黑色!</p>
  <p class="animated">这也是黑色(!important 胜出)</p>
</body>
</html>

2.2 来源与重要性权重

CSS 声明按来源(Origin)和重要性(!important 标志)组合成一个 3×2 矩阵:

普通 重要 (!important)
浏览器样式 最低 第 4 低
用户样式 第 3 低 第 2 高
作者样式 第 2 低 最高(不含过渡)

也就是说,作者 !important > 用户 !important > 浏览器 !important > 作者普通 > 用户普通 > 浏览器普通。

2.3 特异性(Specificity)计算

当多个来源相同、重要性相同的声明冲突时,浏览器会比较特异性。特异性用四组数值表示(通常写作 (a, b, c, d)):

级别 对应选择器类型 计数
a 内联样式 (style="") 1 或 0
b ID 选择器的数量 计数
c 类、伪类、属性选择器的数量 计数
d 元素、伪元素选择器的数量 计数

比较规则:从左到右逐位比较,数值大的胜出。(1,0,0,0) > (0,15,0,0)。

计算示例

/* 选择器                               (a,b,c,d) */
* {}                                   /* (0,0,0,0) */
li {}                                  /* (0,0,0,1) */
li:first-line {}                       /* (0,0,0,2) — 元素 + 伪元素 */
ul li {}                               /* (0,0,0,2) */
ul ol+li {}                            /* (0,0,0,3) */
h1 + *[rel=up] {}                      /* (0,0,1,1) — 属性选择器 = 类级别 */
ul ol li.red {}                        /* (0,0,1,3) */
li.red.level {}                        /* (0,0,2,1) */
#x34y {}                               /* (0,1,0,0) */
#s12:not(FOO) {}                       /* (0,1,0,1) — :not() 本身不计,内部选择器计入 */
.foo:is(.bar, #baz) {}                 /* (0,1,1,0) — :is() 取内部最高特异性 */

重要::not()、:is()、:has() 的特异性取参数列表中最高的选择器的特异性。而 :where() 的特异性始终为 (0,0,0,0)。

完整对比示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <style>
    /* (0,0,0,1) */
    div { color: red; }

    /* (0,0,1,0) */
    .highlight { color: blue; }

    /* (0,0,1,1) */
    div.highlight { color: green; }

    /* (0,1,0,0) */
    #special { color: purple; }

    /* (0,1,1,0) */
    #special.highlight { color: orange; }

    /* (1,0,0,0) — 内联样式 高于所有这些 */
  </style>
</head>
<body>
  <!-- 内联样式特异性 (1,0,0,0),所以这里显示 black -->
  <div id="special" class="highlight" style="color: black;">
    这段文字是什么颜色?
  </div>
  <!-- 答案是 black(内联 > 任何选择器!) -->
</body>
</html>

2.4 位置规则(源顺序)

当特异性完全相同时,后定义的样式覆盖先定义的。

/* 特异性都是 (0,0,1,0) */
.btn { background: blue; }    /* 先定义 */
.btn { background: red; }     /* 后定义 → 生效 */

/* 重要:外部样式表中后面的链接也会覆盖前面的 */
/* link1.css: .btn { color: blue; } */
/* link2.css: .btn { color: red; }  → 生效 */

/* 相同选择器,后出现的优先 */
h1 { color: blue; }
h1 { color: red; }   /* 生效 */

2.5 @layer 级联层

CSS 级联层(@layer)是 CSS 新增的强大功能,允许作者显式控制层的优先级,无需依靠选择器特异性或源顺序。

/* 定义层的优先级顺序:越后面的层优先级越高 */
@layer base, components, utilities;

/* 在层内定义样式 */
@layer base {
  a { color: blue; }                    /* (0,0,0,1) */
}

@layer components {
  .nav-link { color: darkblue; }        /* (0,0,1,0) */
}

@layer utilities {
  .link-reset { color: inherit; }       /* (0,0,1,0) */
}

/* 未放入任何层的样式优先级最高("未分层"层)*/
a { color: black; }                     /* 最终生效 */

无层叠层的样式优先级排序:

@layer A   (最低)
  ↓
@layer B
  ↓
@layer C
  ↓
未分层样式  (最高)

实际应用:

/* 框架/重置层 — 最低优先级 */
@layer reset {
  * { margin: 0; padding: 0; box-sizing: border-box; }
}

/* 组件层 — 中等优先级 */
@layer components {
  .card {
    background: white;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
}

/* 工具层 — 较高优先级 */
@layer utilities {
  .bg-primary { background: #007bff !important; }
}

/* 覆盖层 — 最高优先级(未分层) */
.emergency-banner {
  background: #dc3545 !important;
}

@layer 的优势:即使 @layer reset 中的选择器特异性比 @layer components 高,由于层的顺序,components 仍然会覆盖 reset。这大大简化了大型项目中的样式管理。

2.6 组件级 CSS 策略

结合层叠规则,现代组件级 CSS 常用以下策略:

策略 1:BEM + 特异性控制

/* 所有组件使用相同的特异性级别 */
.card { }
.card__title { }
.card__content { }
/* 不同的组件间用层叠层控制顺序 */

策略 2:CSS Modules / Scoped CSS

/* 框架自动添加独特属性选择器提升特异性 */
/* .Card_title_abc123 { color: blue; } */

策略 3:utility-first(Tailwind)

/* 所有工具类特异性相同,通过层叠层控制 */
.layers-base .text-center { text-align: center; }
/* 用 @layer 控制优先级顺序 */

三、继承(Inheritance)

继承是 CSS 中属性值从父元素自动传递到子元素的机制。理解继承特性对于编写简洁、可维护的样式至关重要。

3.1 继承属性 vs 非继承属性

常见的继承属性:

类别 属性
字体相关 font-family, font-size, font-weight, font-style, font-variant, font
文本相关 color, text-align, text-indent, line-height, letter-spacing, word-spacing, text-transform, direction
可见性 visibility
列表 list-style, list-style-type, list-style-position
光标 cursor
其他 orphans, widows, quotes

常见的非继承属性:

类别 属性
盒模型 width, height, margin, padding, border
布局 display, position, top, right, bottom, left, float, clear, overflow
背景 background, background-color 等
定位 z-index, transform
其他 box-shadow, text-shadow, outline, opacity(文本不继承但容器影响)

3.2 显式继承与控制关键字

CSS 提供了四个通用关键字来控制属性值的行为:

关键字 效果
inherit 强制继承父元素的计算值(即使是非继承属性)
initial 使用属性的初始值(CSS 规范定义的默认值,非浏览器默认)
unset 继承属性 → 表现如 inherit;非继承属性 → 表现如 initial
revert 恢复为浏览器默认样式(重置层叠中更低的来源)
revert-layer 恢复为上一级层叠层的值

3.3 all: unset 重置所有属性

all 属性允许一次性重置元素的所有属性。

/* 完全重置元素的样式 — 相当于元素"裸奔" */
.reset-all {
  all: unset;
}

/* 强制继承所有属性 */
.inherit-all {
  all: inherit;
}

/* 恢复所有属性到初始值 */
.initial-all {
  all: initial;
}

/* 恢复所有属性到浏览器默认 */
.revert-all {
  all: revert;
}

实际应用场景:重置第三方组件或统一规范化:

/* 重置按钮为裸元素(常用于 CSS 框架的 reset) */
.button-reset {
  all: unset;
  display: inline-flex;      /* 重新设置必要的属性 */
  cursor: pointer;
}

/* 在 Shadow DOM 中重置所有宿主样式 */
:host {
  all: initial;
}

警告:all: unset 会重置 display 等属性,通常需要紧接着重新设置 display 值。all: revert 在重置浏览器默认样式后还能保留作者样式表中的普通声明。


四、@规则(At-rules)

@规则是 CSS 中的指令语句,以 @ 开头,用于控制 CSS 的行为、引入外部资源、定义条件规则等。

4.1 @import — 引入外部样式表

/* 在样式表顶部引入其他 CSS 文件 */
@import url('reset.css');
@import url('theme.css') screen and (min-width: 768px);
@import url('print.css') print;

/* 支持媒体查询条件 */
@import 'mobile.css' (max-width: 480px);

注意:@import 必须位于样式表的最顶部(在任何其他规则之前),否则会被忽略。出于性能考虑,在 HTML 中使用 <link> 替代 @import 通常是更好的选择(避免串行下载)。

4.2 @media — 媒体查询

@media 是响应式设计的核心,允许根据设备特性应用条件样式。

4.3 @supports — 特性检测

@supports 允许根据浏览器是否支持特定 CSS 属性/值来决定是否应用样式,是渐进增强的利器。

4.4 @font-face — 自定义字体

@font-face {
  font-family: 'CustomFont';
  src: url('fonts/custom.woff2') format('woff2'),
       url('fonts/custom.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap; /* 控制加载期间的行为 */
}

@font-face {
  font-family: 'CustomFont';
  src: url('fonts/custom-bold.woff2') format('woff2'),
       url('fonts/custom-bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* 使用 */
body {
  font-family: 'CustomFont', 'Noto Sans SC', sans-serif;
}

/* font-display 可选值 */
/* auto      — 浏览器默认行为 */
/* block     — 最多 3 秒不可见,然后降级字体,字体加载完成后切换 */
/* swap      — 立即显示降级字体,字体加载完成后切换(最常用) */
/* fallback  — 100ms 不可见 + 3 秒降级字体,超时后不再切换 */
/* optional  — 100ms 不可见 + 可选降级,让浏览器决定是否使用 */

4.5 @keyframes — 动画关键帧


五、CSS 命名方法论简介

当项目规模增大,良好的 CSS 组织方式变得至关重要。以下是两种主流方法论。

5.1 BEM(Block__Element--Modifier)

BEM 是 Block Element Modifier 的缩写,是一种通过命名约定来保持选择器特异性一致、避免冲突的 CSS 方法论。

组件 含义 示例
Block 独立、可复用的组件 .card
Element Block 的组成部分,依赖 Block 存在 .card__title
Modifier Block 或 Element 的变体状态 .card--featured, .card__title--large

完整示例:

BEM 优势:

  • 所有选择器特异性相同(单层类选择器,(0,0,1,0))
  • 命名即文档——从类名就能看出组件结构
  • 不会出现嵌套选择器导致的特异性竞争

注意(非官方但常见的实践):

/* Block + Element + Modifier 组合 */
.card__title--large { }

/* SCSS 中的 BEM 嵌套写法(输出保持扁平) */
.card {
  &__title {
    &--large { }
  }
  &--featured { }
}

5.2 工具类 CSS(Utility-First)

以 Tailwind CSS 为代表的工具类方法,使用细粒度、单一职责的工具类直接在 HTML 中组合样式。

Tailwind 的核心哲学:

<!-- 传统 CSS -->
<div class="card">
  <h3 class="card__title">标题</h3>
  <p class="card__content">内容</p>
</div>

<!-- Utility-First 方式 -->
<div class="bg-white border border-gray-200 rounded-lg p-4 shadow-md">
  <h3 class="text-lg font-semibold my-3">标题</h3>
  <p class="text-gray-600 leading-relaxed">内容</p>
</div>

Tailwind 优势:

优势 说明
无命名负担 不再需要为组件起名
一致性 所有间距/颜色/字体都来自预设的设计系统
小体积 最终只打包使用到的类(PurgeCSS)
响应式内置 md:flex, lg:text-lg 等前缀
状态变体 hover:bg-blue-600, focus:ring-2
<!-- 响应式卡片示例(使用 Tailwind 类名) -->
<div class="max-w-sm mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
  <div class="md:flex">
    <div class="md:shrink-0">
      <img class="h-48 w-full object-cover md:h-full md:w-48"
           src="image.jpg" alt="图片描述">
    </div>
    <div class="p-8">
      <div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">
        分类标签
      </div>
      <a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">
        文章标题
      </a>
      <p class="mt-2 text-gray-500">文章简介内容……</p>
    </div>
  </div>
</div>

BEM vs Utility-First 对比:

维度 BEM Utility-First
选择器特异性 始终 (0,0,1,0) 始终 (0,0,1,0)
HTML 长度 短,类名少 长,类名多
学习曲线 低 中(需记忆类名)
组件抽取时机 一开始就定义 出现重复时提取
修改样式风险 需改 CSS 文件 限制在设计系统内
团队一致性 依赖命名规范 强一致性(受框架约束)

总结

CSS 选择器、层叠与继承是 CSS 引擎工作的三大基石。理解它们不仅帮助你写出正确的样式,更能让你以 "浏览器的方式" 思考 CSS,从而:

  1. 选择器 — 精确地定位元素,利用特异性规则写出可预测、可维护的样式。善用 :is() 和 :where() 控制特异性,用伪类和伪元素减少 JavaScript 依赖。

  2. 层叠 — 优先级是 CSS 冲突解决的核心。理解来源、重要性、特异性、位置和 @layer 的五层递进关系,从根本上避免 "加 !important" 的恶性循环。

  3. 继承 — 利用继承属性减少重复代码,使用 inherit、initial、unset 和 revert 精确控制属性值传递。

  4. @规则 — @media、@supports、@font-face、@keyframes 和 @layer 扩展了 CSS 的能力边界,使其从静态样式表进化为动态的、条件式的、可编程的样式语言。

  5. 命名方法论 — BEM 和 Utility-First 解决了工程化问题,让团队在大型项目中保持一致的样式策略。

CSS 看似简单,实则深邃。当你真正理解选择器的精度、层叠的神奇和继承的优雅时,你将不再是 "写 CSS",而是 "设计 CSS 系统"。


本文发布于 2024-08-26,涵盖 CSS 选择器 Level 4 规范中的大多数特性。部分较新的特性(如 :has()、@layer、@container)已在主流现代浏览器中广泛支持,建议在生产环境前查阅 Can I Use 确认兼容性。