Skip to content

选择器家族

基于 CSS 现代标准 · 核于 2026-06

速查

  • 基础四类:通用 *、类型 p、类 .btn、ID #main(ID 一页应唯一)
  • 属性选择器全谱:[attr] 存在、[attr="v"] 全等、[attr~="v"] 空格分隔含某词、[attr|="v"] 等于或以 v- 开头、[attr^="v"] 前缀、[attr$="v"] 后缀、[attr*="v"] 子串
  • 属性大小写标记:[attr="v" i] 忽略大小写、[attr="v" s] 强制区分大小写
  • 选择器列表(逗号):h1, h2, .title 是「或」,一处非法整条作废(除非用 :is() / :where() 容错)
  • 复合选择器(无空格)a.btn[href]=同一元素同时满足多个条件,是「与」
  • 四个组合器:后代(空格)、子 >、相邻兄弟 +、后续兄弟 ~
  • 组合器本身不加特异性;选择器只能向「下/后」匹配,向上找父级要靠 :has()
  • 伪类 :hover 取「状态/位置」,伪元素 ::before 造「虚拟元素」——详见下一页

选择器是什么

选择器是一段「匹配规则」,告诉浏览器从 DOM 里挑出哪些元素来套用声明块。按能力可分为四个家族:基础选择器、属性选择器、组合器、伪类与伪元素。前三家是本页主角,伪类伪元素在 下一页 单独展开。

基础选择器

通用选择器 *

匹配任何元素:

css
* {
  box-sizing: border-box; /* 经典全局重置 */
}

它的特异性为 0-0-0(不加任何权重),所以常被用作不污染特异性的全局基线。

类型(元素)选择器

直接写标签名,匹配所有该类型元素:

css
section {
  padding: 2em;
}

类选择器

. 开头,匹配 class 属性里含该名字的元素——一个元素可有多个类,多个元素可共享一个类。类是 CSS 复用的主力。

css
.note {
  color: #555;
}

类名不能以数字开头

.1col 是非法的;要么改名(.col-1),要么转义(.\31 col,极少这么做)。实践中直接用 col-1 这类命名即可。

ID 选择器

# 开头,匹配 id 属性。HTML 规定 id 在一个文档内唯一,所以 ID 选择器应只命中一个元素:

css
#main-nav {
  position: sticky;
}

ID 特异性极高(1-0-0),容易引发覆盖困难,CSS 里通常优先用类、把 ID 留给锚点定位和 JS 钩子(见 特异性计算)。

属性选择器

[ ] 按元素的属性及其值匹配,是表单、链接、国际化场景的利器。

css
/* 1) 存在即匹配(不看值) */
[disabled] {
  opacity: 0.5;
}

/* 2) 值全等 */
[type="email"] {
  border-color: teal;
}

按「值如何匹配」,还有一组子串/词匹配变体:

写法含义命中示例(属性值)
[attr]含有该属性任意有 attr 的元素
[attr="val"]完全等于 valval
[attr~="val"]值是空格分隔的词表且含 val 这个词"a val b"
[attr|="val"]等于 val或以 val- 开头(语言子标签常用)valval-xval-CN
[attr^="val"]val 开头(前缀)valueval123
[attr$="val"]val 结尾(后缀)myvala.val
[attr*="val"]含子串 valxvalymyval

实战示例:

css
/* 外部链接加图标:href 以 https 开头 */
a[href^="https"]::after {
  content: " ↗";
}

/* PDF 链接特殊标记:href 以 .pdf 结尾 */
a[href$=".pdf"] {
  font-weight: 600;
}

/* 工具类前缀批量命中:class 含 "btn-" 子串 */
[class*="btn-"] {
  cursor: pointer;
}

大小写敏感标记 i / s

属性值匹配默认是否区分大小写取决于文档语言(HTML 里多数属性值大小写不敏感,但比如 class 的值是敏感的)。可显式加标记覆盖:

css
/* i:忽略大小写——.PNG / .Png / .png 都命中 */
[src$=".png" i] {
  border: 1px solid #ccc;
}

/* s:强制区分大小写 */
[data-state="OPEN" s] {
  display: block;
}

标记写在结束 ] 前、值之后,用空格隔开。

选择器列表与复合选择器:「或」与「与」

这两个概念长得像、含义相反,是初学者最常混淆的地方。

选择器列表(逗号 = 或)

用逗号把多个选择器并列,等于「对其中任意一个命中的元素都套用这套声明」:

css
h1,
h2,
.title,
[role="heading"] {
  font-family: "Source Han Serif", serif;
}

列表里一处非法,整条规则作废

传统选择器列表是「不容错」的:只要列表中任何一个选择器是浏览器不认识的(比如新伪类),整条规则都会被丢弃,连合法的部分也一起失效。要让它「容错」,得把可能失败的部分包进 :is():where()(它们是 forgiving 列表,会忽略其中非法项)。详见 伪类与伪元素

复合选择器(无空格 = 与)

把多个简单选择器紧贴在一起、不留空格,表示「同时满足全部条件的同一个元素」:

css
a.button {
  /* 既是 <a> 又有 button 类 */
}
input[type="checkbox"]:checked {
  /* <input> + type 为 checkbox + 处于选中态 */
}

注意书写约束:类型选择器(如 a)若出现,必须写在最前面a.button 合法,.buttona 会被当成另一个类名。

组合器:表达元素间的关系

组合器是夹在两个选择器中间的符号(或空格),用来表达 DOM 里的结构关系。四种如下。

后代组合器(空格)

css
article a {
  /* <article> 内部任意深度的 <a> 都命中 */
}

最宽松,递归匹配所有后代。

子组合器 >

css
.menu > li {
  /* 只命中 .menu 的直接子 <li>,孙子级不算 */
}

只匹配直接子元素,比后代组合器精确、也更可控。

相邻兄弟组合器 +

css
h2 + p {
  /* 紧跟在某个 <h2> 之后的、第一个同级 <p> */
  margin-top: 0;
}

只命中紧挨着、且同一父级的下一个兄弟。

后续兄弟组合器 ~

css
h2 ~ p {
  /* 某个 <h2> 之后的所有同级 <p>(不必紧挨) */
}

命中其后所有符合条件的同级兄弟。

一个经典组合——「猫头鹰选择器」给所有相邻子元素加间距:

css
.stack > * + * {
  margin-top: 1rem; /* 每个直接子元素,只要前面还有兄弟,就加上间距 */
}

组合器不加特异性,且方向「只能向下/向后」

组合器符号本身(> + ~ 和空格)对特异性贡献为 0,只有两侧的选择器计权重。更关键的限制:CSS 选择器历来只能向下(后代/子)或向后(兄弟)匹配,无法「选中含有某子元素的父级」或「选中某元素前面的兄弟」。这个十几年的痛点,由 :has() 关系选择器解决(见下一页)。

一张表收束选择器全谱

家族写法示例命中
通用*所有元素
类型ph1该标签的所有元素
.card含该类的元素
ID#hero该 id 的唯一元素
属性[type="text"][href^="/"]按属性 / 值匹配
选择器列表(或)h1, h2, .title任一命中即套用
复合(与)a.btn[href]同时满足全部条件
后代nav a后代任意层级
ul > li直接子元素
相邻兄弟h2 + p紧邻的下一个兄弟
后续兄弟h2 ~ p之后的所有同级兄弟
伪类:hover:nth-child(2)状态 / 位置(下一页)
伪元素::before::marker虚拟元素(下一页)

小结

基础选择器解决「是什么」,属性选择器解决「带什么属性」,组合器解决「在结构里处于什么关系」。但选择器最有表现力的部分——能感知交互状态、文档结构,甚至「反向」选中父级的伪类伪元素,还在后头:伪类与伪元素