选择器家族
基于 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 里挑出哪些元素来套用声明块。按能力可分为四个家族:基础选择器、属性选择器、组合器、伪类与伪元素。前三家是本页主角,伪类伪元素在 下一页 单独展开。
基础选择器
通用选择器 *
匹配任何元素:
* {
box-sizing: border-box; /* 经典全局重置 */
}它的特异性为 0-0-0(不加任何权重),所以常被用作不污染特异性的全局基线。
类型(元素)选择器
直接写标签名,匹配所有该类型元素:
section {
padding: 2em;
}类选择器
以 . 开头,匹配 class 属性里含该名字的元素——一个元素可有多个类,多个元素可共享一个类。类是 CSS 复用的主力。
.note {
color: #555;
}类名不能以数字开头
.1col 是非法的;要么改名(.col-1),要么转义(.\31 col,极少这么做)。实践中直接用 col-1 这类命名即可。
ID 选择器
以 # 开头,匹配 id 属性。HTML 规定 id 在一个文档内唯一,所以 ID 选择器应只命中一个元素:
#main-nav {
position: sticky;
}ID 特异性极高(1-0-0),容易引发覆盖困难,CSS 里通常优先用类、把 ID 留给锚点定位和 JS 钩子(见 特异性计算)。
属性选择器
用 [ ] 按元素的属性及其值匹配,是表单、链接、国际化场景的利器。
/* 1) 存在即匹配(不看值) */
[disabled] {
opacity: 0.5;
}
/* 2) 值全等 */
[type="email"] {
border-color: teal;
}按「值如何匹配」,还有一组子串/词匹配变体:
| 写法 | 含义 | 命中示例(属性值) |
|---|---|---|
[attr] | 含有该属性 | 任意有 attr 的元素 |
[attr="val"] | 值完全等于 val | val |
[attr~="val"] | 值是空格分隔的词表且含 val 这个词 | "a val b" |
[attr|="val"] | 值等于 val或以 val- 开头(语言子标签常用) | val、val-x、val-CN |
[attr^="val"] | 值以 val 开头(前缀) | value、val123 |
[attr$="val"] | 值以 val 结尾(后缀) | myval、a.val |
[attr*="val"] | 值含子串 val | xvaly、myval |
实战示例:
/* 外部链接加图标: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 的值是敏感的)。可显式加标记覆盖:
/* i:忽略大小写——.PNG / .Png / .png 都命中 */
[src$=".png" i] {
border: 1px solid #ccc;
}
/* s:强制区分大小写 */
[data-state="OPEN" s] {
display: block;
}标记写在结束 ] 前、值之后,用空格隔开。
选择器列表与复合选择器:「或」与「与」
这两个概念长得像、含义相反,是初学者最常混淆的地方。
选择器列表(逗号 = 或)
用逗号把多个选择器并列,等于「对其中任意一个命中的元素都套用这套声明」:
h1,
h2,
.title,
[role="heading"] {
font-family: "Source Han Serif", serif;
}列表里一处非法,整条规则作废
传统选择器列表是「不容错」的:只要列表中任何一个选择器是浏览器不认识的(比如新伪类),整条规则都会被丢弃,连合法的部分也一起失效。要让它「容错」,得把可能失败的部分包进 :is() 或 :where()(它们是 forgiving 列表,会忽略其中非法项)。详见 伪类与伪元素。
复合选择器(无空格 = 与)
把多个简单选择器紧贴在一起、不留空格,表示「同时满足全部条件的同一个元素」:
a.button {
/* 既是 <a> 又有 button 类 */
}
input[type="checkbox"]:checked {
/* <input> + type 为 checkbox + 处于选中态 */
}注意书写约束:类型选择器(如 a)若出现,必须写在最前面;a.button 合法,.buttona 会被当成另一个类名。
组合器:表达元素间的关系
组合器是夹在两个选择器中间的符号(或空格),用来表达 DOM 里的结构关系。四种如下。
后代组合器(空格)
article a {
/* <article> 内部任意深度的 <a> 都命中 */
}最宽松,递归匹配所有后代。
子组合器 >
.menu > li {
/* 只命中 .menu 的直接子 <li>,孙子级不算 */
}只匹配直接子元素,比后代组合器精确、也更可控。
相邻兄弟组合器 +
h2 + p {
/* 紧跟在某个 <h2> 之后的、第一个同级 <p> */
margin-top: 0;
}只命中紧挨着、且同一父级的下一个兄弟。
后续兄弟组合器 ~
h2 ~ p {
/* 某个 <h2> 之后的所有同级 <p>(不必紧挨) */
}命中其后所有符合条件的同级兄弟。
一个经典组合——「猫头鹰选择器」给所有相邻子元素加间距:
.stack > * + * {
margin-top: 1rem; /* 每个直接子元素,只要前面还有兄弟,就加上间距 */
}组合器不加特异性,且方向「只能向下/向后」
组合器符号本身(> + ~ 和空格)对特异性贡献为 0,只有两侧的选择器计权重。更关键的限制:CSS 选择器历来只能向下(后代/子)或向后(兄弟)匹配,无法「选中含有某子元素的父级」或「选中某元素前面的兄弟」。这个十几年的痛点,由 :has() 关系选择器解决(见下一页)。
一张表收束选择器全谱
| 家族 | 写法示例 | 命中 |
|---|---|---|
| 通用 | * | 所有元素 |
| 类型 | p、h1 | 该标签的所有元素 |
| 类 | .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 | 虚拟元素(下一页) |
小结
基础选择器解决「是什么」,属性选择器解决「带什么属性」,组合器解决「在结构里处于什么关系」。但选择器最有表现力的部分——能感知交互状态、文档结构,甚至「反向」选中父级的伪类伪元素,还在后头:伪类与伪元素。