← [ BACK_TO_NOTES ]

CSS 选择器优先级与组合

CSS 选择器的优先级计算、组合选择器、伪类与伪元素的使用边界。

#frontend #css #concept #growing

[!info] related notes

CSS 选择器优先级与组合

[!note] 边界 特异性(specificity)的 canonical 规则与层叠比较见 CSS 优先级与特异性。本文保留选择器组合、匹配方式以及“组合后如何影响特异性”的速查,不再把 CSS Specificity 作为自身身份别名。

定义

选择器组合决定匹配哪些元素;特异性是匹配之后、层叠解决声明冲突时的一个比较维度。来源、important 和层叠层等条件先于特异性比较。

优先级计算

更准确地说,selector specificity 通常按三列比较:ID、CLASS、TYPE。内联 style 属于声明来源语境;!important 会改变层叠比较层级,二者都不应当被塞进 selector specificity 本身。

  • ID:ID 选择器数量
  • CLASS:类、属性选择器、伪类数量
  • TYPE:元素选择器、伪元素数量

进入特异性比较后,先比较 ID,再比较 CLASS,最后比较 TYPE;三列相同时,再按作用域接近程度和源顺序等后续规则处理。

/* specificity: (0, 0, 1) */
p { color: black; }

/* specificity: (0, 1, 0) — 更高 */
.text { color: blue; }

/* specificity: (1, 0, 0) — 更高 */
#title { color: red; }

/* specificity: (0, 1, 1) */
p.intro { color: green; }

/* specificity: (0, 1, 2) */
div p.intro { color: purple; }

常见选择器的优先级

选择器优先级
*(通配符)(0, 0, 0)
p(元素)(0, 0, 1)
.class(类)(0, 1, 0)
:hover(伪类)(0, 1, 0)
[type="text"](属性)(0, 1, 0)
#id(1, 0, 0)

特殊情况

  • 通配符 * 不影响优先级
  • :is()、:not()、:has() 取参数列表中最高的特异性;:where() 连同参数始终为 0
  • 只有前面的层叠条件和作用域接近程度等也相同时,源顺序才决定胜负

组合选择器

/* 后代选择器:匹配 .container 内所有 p */
.container p { }

/* 子元素选择器:只匹配直接子元素 */
.nav > li { }

/* 相邻兄弟选择器:紧跟其后的兄弟 */
h2 + p { }

/* 通用兄弟选择器:之后的所有兄弟 */
h2 ~ p { }

组合选择器对优先级的影响

/* 后代选择器:两个元素选择器 */
div p { }         /* (0, 0, 2) */

/* 交集选择器:类 + 元素 */
p.active { }      /* (0, 1, 1) */

/* 多类选择器 */
.btn.primary { }  /* (0, 2, 0) */

常用伪类

/* 状态伪类 */
a:hover { }
input:focus { }
button:active { }
a:visited { }

/* 结构伪类 */
li:first-child { }
li:last-child { }
li:nth-child(2n) { }    /* 偶数行 */
li:nth-child(3n+1) { }  /* 每三个一组的第一个 */
li:not(.disabled) { }

/* 表单伪类 */
input:valid { }
input:invalid { }
input:required { }
input:disabled { }
input:checked { }

常用伪元素

/* 虚拟内容 */
.icon::before { content: "★"; }
.tooltip::after { content: attr(data-tip); }

/* 文本样式 */
p::first-line { font-weight: bold; }
p::first-letter { font-size: 2em; }

/* 选中样式 */
::selection { background: yellow; }

/* 占位符 */
input::placeholder { color: #999; }

实际开发中的经验

避免过度嵌套

/* 不推荐:高优先级,难覆盖 */
body .main .content .card .title .text { }

/* 推荐:低优先级,易维护 */
.card-text { }

不要滥用 !important

/* 不推荐 */
.btn { background: red !important; }

/* 推荐:用更具体的选择器 */
.btn.btn-primary { background: red; }

伪类 vs 伪元素

  • 伪类用一个冒号 : — 描述元素的状态
  • 伪元素用两个冒号 :: — 描述元素的虚拟部分
  • 旧式 :before / :after 仍被兼容;新代码使用双冒号,以区分伪元素与伪类

边界

  • 内联声明与选择器声明的比较属于完整 cascade;不要把它当作 selector specificity 的“第四列”
  • cascade layer 的顺序在 specificity 之前比较,因此不同 layer 之间不能只靠 specificity 判断胜负
  • 优先级是选择器级别的,不是属性级别的
  • 来源、important、层、特异性与作用域接近程度等都相同时,后出现的声明胜出
  • 伪类和属性选择器的优先级相同

一句话记忆法

先确认匹配,再按完整层叠规则比较;特异性按 ID、类、类型逐列比较。不要把加深选择器当作通用修复手段。

创建于 2026/5/27 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本