技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTCSS

CSS 选择器总结

所属馆藏
CSS
文件格式
Markdown
原始路径
CSS/12-css选择器总结
本文目录9 个章节
  1. 一、基础选择器
  2. 二、属性选择器
  3. 三、组合选择器
  4. 四、伪类选择器
  5. 五、伪元素选择器
  6. 六、选择器优先级
  7. 七、选择器的维护建议
  8. 总结
  9. 参考资料

CSS 选择器总结

Category(分类): CSS Status: 已整理

CSS 选择器用于从文档中匹配元素,并为匹配到的元素应用样式。常见选择器可以分为:

  • 基础选择器;
  • 属性选择器;
  • 组合选择器;
  • 伪类选择器;
  • 伪元素选择器。

选择器匹配到元素后,最终是否生效还要受到层叠、选择器优先级、继承和样式声明顺序影响。

一、基础选择器

1. ID 选择器

ID 选择器使用 # 加上 ID 名称,匹配具有对应 id 属性的元素:

<div id="page">我是 ID 选择器</div>
#page {
  color: #fff;
  background: #000;
}

同一个页面中,id 通常应保持唯一。ID 选择器优先级较高,不建议把它作为组件样式的主要选择方式,否则后续覆盖样式会比较困难。

2. 类选择器

类选择器使用 . 加上 class 名称,匹配具有对应类名的元素:

<ul>
  <li class="list-item">1</li>
  <li class="list-item">2</li>
  <li class="list-item">3</li>
</ul>
.list-item {
  color: red;
  font-size: 16px;
}

类选择器可以复用,也可以给同一元素添加多个类:

<div class="card active"></div>
.card.active {
  border-color: #168bf5;
}

3. 通配符选择器

通配符选择器使用 *,可以匹配范围内的所有元素:

* {
  margin: 0;
  padding: 0;
}

现代项目中更常见的基础重置写法是:

*,
*::before,
*::after {
  box-sizing: border-box;
}

通配符选择器的主要问题是影响范围很广,可能带来意外样式和维护成本。不能简单断言它一定“性能很差”,现代浏览器会对选择器进行优化,实际影响还取决于 DOM 规模和样式变化频率。

4. 标签选择器

标签选择器直接使用 HTML 标签名:

li {
  font-size: 20px;
}

它适合设置元素的基础样式或重置样式,例如:

h1,
h2,
p {
  margin: 0;
}

标签选择器会匹配页面中所有相同类型的元素,因此组件样式中通常更推荐使用类选择器进行限制:

.article-list li {
  margin-block: 0.5rem;
}

二、属性选择器

属性选择器使用方括号 [] 根据元素属性进行匹配。属性值建议使用引号,以提高可读性和兼容不同取值的能力。

1. [attr]:具有某个属性

a[href] {
  color: red;
}

它会匹配具有 href 属性的 <a> 元素,不要求属性值是什么。

2. [attr="value"]:属性值完全相等

<input type="text" value="xuanze">
input[type="text"] {
  color: red;
}

完全匹配属性值:

<input class="input text" type="text" value="xuanze">
input[class="input text"] {
  color: red;
}

上面的写法要求整个 class 属性值完全一致,以下情况都不会匹配:

<input class="text input" type="text">
<input class="input text large" type="text">

如果想匹配 class 中的一个独立单词,应使用 [class~="input"]

3. [attr~="value"]:空格分隔的单词匹配

<input class="input text">
input[class~="input"] {
  color: red;
}

它匹配以空格分隔的独立单词 input,但不会匹配:

<input class="input-text">

4. [attr|="value"]:完全相等或以 value- 开头

<div class="article"></div>
<div class="article-title"></div>
<div class="article-content"></div>
<div class="article_footer"></div>
div[class|="article"] {
  color: red;
}

会匹配 articlearticle-titlearticle-content,不会匹配 article_footer。注意正确语法是 |=,不是 |

5. [attr^="value"]:属性值以指定内容开头

div[class^="article"] {
  color: red;
}

会匹配以 article 开头的属性值,例如 article-titlearticle_footer

它不是正则表达式,而是 CSS 定义的字符串前缀匹配。如果写成 artice,由于拼写错误,将匹配不到 article 开头的值。

6. [attr$="value"]:属性值以指定内容结尾

a[href$=".pdf"] {
  padding-right: 1.2em;
}

上面会匹配 href.pdf 结尾的链接。

7. [attr*="value"]:属性值包含指定字符串

[class*="icon"] {
  display: inline-block;
}

它匹配属性值中包含 icon 子字符串的元素,不要求它是空格分隔的独立单词。

8. 属性值匹配的大小写标志

可以在属性值后增加 i,进行 ASCII 范围内的大小写不敏感匹配:

input[type="TEXT" i] {
  color: red;
}

默认是否区分大小写还会受到 HTML 属性定义和文档语言规则影响,不能对所有属性一概而论。

三、组合选择器

1. 后代选择器

后代选择器使用空格分隔多个选择器,匹配前一个元素内部任意层级的后代:

<div class="page">
  <div class="article">
    <p>文章内容</p>
  </div>
  <p>页面内容</p>
</div>
.page p {
  color: gold;
  font-size: 20px;
}

.page p 会匹配两个 <p>,因为它们都是 .page 的后代。

2. 子元素选择器

子元素选择器使用 >,只匹配直接子元素:

.page > p {
  color: red;
}

上面的规则只匹配 .page 的直接 <p>,不会匹配嵌套在 .article 内部的 <p>

3. 相邻兄弟选择器

相邻兄弟选择器使用 +,匹配紧跟在前一个元素后面的同级兄弟元素:

h1 + p {
  margin-top: 20px;
  color: black;
}

只有 h1 后面紧邻的第一个符合条件的 <p> 会被匹配,中间不能有其他元素。

4. 通用兄弟选择器

通用兄弟选择器使用 ~,匹配前一个元素之后的所有符合条件的同级兄弟元素:

h1 ~ p {
  color: red;
}

它只匹配后面的兄弟,不匹配前面的元素,也不匹配嵌套后代。

5. 交集选择器

交集选择器把多个简单选择器连续写在一起,中间不能有空格:

.list-item.active {
  color: red;
  font-size: 20px;
}

它匹配同时具有 list-itemactive 两个类的元素。

以下写法含义不同:

.list-item .active {
  /* 匹配 .list-item 内部的 .active 后代 */
}

6. 并集选择器

并集选择器使用逗号分隔多个选择器,让多个选择器共享同一组声明:

h1,
h2,
p {
  margin: 0;
  padding: 0;
}

逗号分隔的每一项都是一个独立选择器,某一项语法错误时可能影响整个规则,因此建议分行书写。

四、伪类选择器

伪类使用一个冒号 :,用于根据元素状态、位置或结构条件进行匹配。

1. 链接和交互状态

:link {
  /* 未访问的链接 */
}

:visited {
  /* 已访问的链接 */
}

:hover {
  /* 指针悬停或其他指针交互状态 */
}

:active {
  /* 元素处于激活过程,例如按下按钮但尚未释放 */
}

:focus {
  /* 元素获得焦点 */
}

:focus-visible {
  /* 浏览器判断应显示明显焦点指示时 */
}

:link:visited 主要用于链接。:visited 出于隐私保护只能应用有限的样式属性。

:active 不是“点击后一直保持选中”,通常只在激活交互期间生效。键盘可访问性场景应保留清晰的 :focus:focus-visible 样式。

链接样式经常按照以下顺序书写,以减少相互覆盖:

/* link, visited, focus, hover, active */
a:link {
  color: #168bf5;
}

a:visited {
  color: #7048e8;
}

a:focus-visible {
  outline: 2px solid currentColor;
}

a:hover {
  text-decoration: underline;
}

a:active {
  color: #d6336c;
}

2. 表单状态

input:checked {
  accent-color: #168bf5;
}

input:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

input:enabled {
  cursor: text;
}

option:checked {
  font-weight: bold;
}

:checked 不只适用于 radiocheckbox,也可以匹配被选中的 <option>。不同表单控件对可应用样式的支持可能有所差异。

3. 结构伪类

:empty

匹配没有子节点的元素:

.box:empty {
  display: none;
}

空白文本节点也可能使元素不再符合 :empty,因此 HTML 中的换行和空格需要注意。

:first-child:last-child

li:first-child {
  color: red;
}

li:last-child {
  color: blue;
}

它们判断的是元素在父元素所有子元素中的位置,而不是同类型元素中的位置。

<div>
  <p>第一个子元素</p>
  <li>第二个子元素</li>
</div>

此时 li:first-child 不会匹配 <li>,因为它不是父元素的第一个子元素。

如果想匹配同类型元素中的第一个或最后一个,应使用:

li:first-of-type {
  color: red;
}

li:last-of-type {
  color: blue;
}

:nth-child(an + b)

li:nth-child(2n + 1) {
  background: #f5f5f5;
}

这会匹配父元素中位置为 1、3、5、7... 的子元素,但位置计算包含所有子元素,不是只统计 li

li:nth-last-child(2n + 1) {
  background: #f5f5f5;
}

:nth-last-child() 从父元素末尾开始计算。

如果需要按同类型元素计算,应使用:

li:nth-of-type(2n + 1) {
  background: #f5f5f5;
}

:only-child:only-of-type

.item:only-child {
  border: 1px solid red;
}

p:only-of-type {
  color: green;
}
  • :only-child:元素是父元素唯一的子元素;
  • :only-of-type:元素是父元素中唯一的同类型元素。

4. 现代常用伪类

:not()

排除满足条件的元素:

.button:not(.disabled) {
  cursor: pointer;
}

:is()

将多个选择器组合为一个匹配条件:

:is(h1, h2, h3) {
  line-height: 1.2;
}

:where()

功能类似 :is(),但其特异性为零,适合编写容易被覆盖的基础样式:

:where(.card, .panel) {
  border-radius: 8px;
}

:has()

根据后代或相邻关系选择元素:

.card:has(img) {
  padding-top: 0;
}

使用前应确认目标浏览器支持情况,并注意复杂选择器可能增加维护成本。

其他常见伪类还包括:

:root       /* 文档根元素 */
:target     /* URL 片段指向的目标元素 */
:required   /* 必填表单控件 */
:valid      /* 通过约束验证的表单控件 */
:invalid    /* 未通过约束验证的表单控件 */

五、伪元素选择器

伪元素使用两个冒号 ::,用于选择元素的某个虚拟部分或生成内容。伪元素不是独立的真实 DOM 节点。

1. ::first-line

设置块容器第一行的样式:

.article::first-line {
  font-weight: bold;
}

第一行会随着容器宽度、字体和内容变化而变化,因此不能把它理解为固定的文本节点。

2. ::first-letter

设置文本开头的首个排版字符:

.article::first-letter {
  float: left;
  margin-right: 0.25em;
  font-size: 2.5em;
  line-height: 1;
}

::first-line::first-letter 有适用的布局条件,主要用于块容器等适合的盒子,不是所有行内元素都能使用。

3. ::before::after

它们可以在元素内容的前后生成伪元素:

.badge::before {
  content: '提示:';
  color: #d6336c;
}

.badge::after {
  content: '';
  display: block;
  clear: both;
}

::before::after 通常需要设置 content 才会生成。生成的内容属于 CSS 呈现结果,不会作为真实 DOM 节点出现在 HTML 结构中。

JavaScript 不能直接使用 querySelector('::before') 查询它们,但可以通过修改宿主元素的类名、CSS 变量或内联样式间接控制:

.button::before {
  content: var(--label, '提交');
}
button.style.setProperty('--label', '"加载中"')

4. ::selection

设置用户选中的文本样式:

::selection {
  color: #fff;
  background: #168bf5;
}

它针对的是文本选区,不是整个元素,并且可用 CSS 属性受到浏览器限制。

5. 单冒号和双冒号

现代 CSS 推荐:

  • 伪类使用一个冒号,例如 :hover
  • 伪元素使用两个冒号,例如 ::before

部分早期伪元素写法,如 :before:after,仍可能得到浏览器兼容支持,但新代码建议使用双冒号。

六、选择器优先级

当多个规则同时匹配同一个元素时,需要根据层叠和选择器特异性决定最终样式。常见特异性由高到低大致为:

  1. !important 声明(还要结合来源和层叠层判断);
  2. 行内样式;
  3. ID 选择器;
  4. 类选择器、属性选择器、伪类;
  5. 标签选择器、伪元素;
  6. 通配符和继承样式。

例如:

#page .title {
  color: red;
}

.page .title {
  color: blue;
}

#page .title 包含一个 ID,因此通常优先级高于 .page .title

!important 不应作为常规解决冲突的手段。更好的做法是降低选择器嵌套、整理组件边界和调整层叠顺序。

需要特别注意:

  • :where() 的特异性为零;
  • :is():not():has() 的特异性取参数列表中最高的那一项;
  • 选择器特异性相同时,后声明的规则通常覆盖先声明的规则;
  • 特异性只在相同层叠来源和层叠层条件下比较。

七、选择器的维护建议

  1. 组件样式优先使用语义清晰的类选择器;
  2. 不要过度依赖 ID 选择器;
  3. 避免过深的后代选择器,例如 .page .content .list ul li span
  4. 使用 >+~ 明确表达父子和兄弟关系;
  5. 属性选择器适合状态和语义属性匹配,不要把复杂业务逻辑全部塞进属性字符串;
  6. 使用 :where() 编写低特异性的基础样式;
  7. 使用 :focus-visible 保留键盘用户可见的焦点状态;
  8. 不要为了覆盖样式而滥用 !important
  9. 选择器性能不要只看单个符号,要结合 DOM 规模、动态更新频率和可维护性判断;
  10. 使用现代伪类前确认项目的浏览器支持范围。

总结

  • #id 选择器匹配 ID,类选择器匹配 class,标签选择器匹配元素类型;
  • * 的影响范围最广,常用于基础重置,但要注意维护范围;
  • 属性选择器可以进行存在、完全相等、空格单词、连字符前缀、前缀、后缀和子字符串匹配;
  • ^=$=*= 不是正则表达式;
  • 空格表示后代,> 表示直接子元素,+ 表示相邻兄弟,~ 表示后续所有兄弟;
  • 多个简单选择器连续书写表示交集,逗号表示并集;
  • :first-child 判断所有子元素的位置,:first-of-type 判断同类型元素的位置;
  • :nth-child() 的位置计算包括所有子元素;
  • :active 表示激活过程,:focus:focus-visible 表示焦点状态;
  • 伪元素不是真实 DOM 节点,::before::after 通常需要 content
  • 现代项目还应掌握 :not():is():where():has() 等伪类;
  • 选择器最终效果还会受到特异性、层叠顺序、继承和声明顺序影响。

参考资料

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS