CSS 选择器优先级与组合

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

#tech / dev / frontend #resource / css #type / concept #status / growing

[!info] related notes

CSS 选择器优先级与组合

定义

选择器优先级(Specificity)是浏览器决定”当多条规则冲突时,哪条生效”的机制。它不是简单的”后写的覆盖先写的”,而是一套基于选择器类型的权重计算系统。

优先级计算

优先级用一个四元组 (a, b, c, d) 表示:

  • a!important(尽量避免使用)
  • b:ID 选择器的数量
  • c:类选择器、属性选择器、伪类的数量
  • d:元素选择器、伪元素的数量

比较规则:从左到右逐位比较,数值大的优先。

/* 优先级: (0, 0, 0, 1) */
p { color: black; }

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

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

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

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

常见选择器的优先级

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

特殊情况

  • 通配符 * 不影响优先级
  • :not() 本身不计优先级,但其参数计
  • :is():where() 中,:where() 的优先级始终为 0
  • 相同优先级时,后定义的规则覆盖先定义的

组合选择器

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

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

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

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

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

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

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

/* 多类选择器 */
.btn.primary { }  /* (0, 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 常写成 :before:after

边界

  • 内联样式(style="")优先级高于所有选择器(除了 !important
  • @layer 中的层叠顺序可以覆盖优先级规则
  • 优先级是选择器级别的,不是属性级别的
  • 相同优先级、相同来源时,后出现的规则覆盖先出现的
  • 伪类和属性选择器的优先级相同

一句话记忆法

优先级按 ID > 类 > 元素 比较;伪类看状态(:hover),伪元素看部分(::before);少用 !important,用更具体的选择器。

创建于 2026/5/27 更新于 2026/5/27