编程语言研究书库

选择器 — 怎么选中你想改的那个元素

选择器 — 怎么选中你想改的那个元素

这一章讲一件事: 规则里的「选中谁」可以怎么写。 共六类思路:按标签、按类、按 ID、按属性、按状态、按元素之间的关系。 读完你能给一段 HTML 配出「只选中那几颗」的选择器,也知道什么时候该停手别写太长。

1. 这一章在全书链条里的位置

上一章立了规则的结构:选择器 + 声明块。这一章把前半段展开—— 它是「选中」(targeting)这一环的完整语法。但选中了不等于生效: 两条规则选中同一个元素时谁赢,是下一章(层叠与特异性)的事; 本章只管「选得中、选得准、别多选」。

2. 顶层全景:一张 HTML,六种选法

主线例子的输入,一段很常见的导航 HTML:

<nav class="menu">
  <ul>
    <li><a href="/">首页</a></li>
    <li class="active"><a href="/blog">博客</a></li>
  </ul>
</nav>

图说:<nav> 套着 <ul>(无序列表),里面两个 <li>(列表项)各套一个 <a>(链接); 第二个 <li> 带类名 active,第二个链接的地址是 /blog。

对着它,六种选法各选中几颗:

nav              → 选标签:2 个 <li> 之外的 <nav> 本体,1 个
.menu            → 选类:<nav>,1 个
li               → 选标签:两个 <li>,2 个
.active          → 选类:第二个 <li>,1 个
a[href="/blog"]  → 选属性:第二个 <a>,1 个
li.active a      → 组合:第二个 <li> 里的 <a>,1 个

下面逐类讲清。

3. 核心原理:六类选择器

按标签、按类、按 ID:三个基本件

标签选择器(type selector)直接写标签名:p、h1、div——选中页面上所有这个标签。

类选择器(class selector)写 .类名:.highlight 选中所有带 class="highlight" 的元素。 类是给元素贴的标签,一个元素可以贴好几个类(class="card highlight"), 一个类可以贴在任意多个元素上——所以类是日常样式的主力。

ID 选择器写 #id名:#main-header 选中 id="main-header" 的那个元素。 ID 在一个 HTML 页面里必须唯一1——这是 HTML 的规矩,不是 CSS 的。 书里给的使用建议很硬:样式尽量别用 ID,因为它的特异性太高,后面很难覆盖(第 03 章展开)。

这三个里有两个细节容易栽:

类名和 ID 区分大小写。 .box 和 .Box 是两个不同的类2——HTML 里的类名是区分大小写的, CSS 侧必须一字不差地对上。

一个空格之差,意义全变。 div.active(无空格)选中「带 active 类的 <div>」; div .active(有空格)选中「<div> 里面的、任何带 active 类的元素」3。 前者是同一个元素的两种条件,后者是两层元素的关系——这是初学者最常写错的一处。

按属性选:属性选择器

input[type="text"]   /* 只选「类型是文本」的输入框 */
a[target="_blank"]   /* 只选「新窗口打开」的链接 */

[属性] 或 [属性="值"]:按 HTML 标签上挂的属性来选4。 文本框得到蓝边框、新窗口链接加粗——这是表单一章的基础工具。

按状态选:伪类(pseudo-class)

button:hover        /* 鼠标悬停时 */
li:nth-child(odd)   /* 排在奇数位的 <li> */
input:focus         /* 被 Tab 键或点击选中时 */

伪类选中的是「处于某种状态的元素」,写法是 选择器:状态名。 状态可以是用户交互(悬停 hover、聚焦 focus),也可以是文档里的位置 (第一个孩子 first-child、第 n 个孩子 nth-child(n)、取反 not())5。 它解决的是「同一个元素,用户碰没碰它,长得不一样」这一类问题。

按部位选:伪元素(pseudo-element)

p::first-letter              /* 每段的首字母 */
.required::after             /* 元素内容之后的位置 */

伪元素选中的是「元素内部的某个部位」,写法用双冒号 ::—— 比如首字母、第一行、内容之前(::before)、内容之后(::after)、占位提示文字(::placeholder)。 书里那个例子:.required::after { content: " *"; color: red; } 会在每个带 required 类的元素后面 缀一颗红星6——表单的「必填」星号就是这么来的。

单双冒号是两套东西,别混:单冒号管状态,双冒号管部位,这是现代 CSS 的规矩7。

按关系选:组合器(combinator)

四种,记住一张表:

名字写法选中什么(回到主线例子)
后代 descendantA BB 只要是 A 里面的都算:.menu a 选中 2 个链接
子 childA > BB 必须是 A 的直接孩子:ul > li 选中 2 个,.menu > a 选中 0 个(a 是孙子)
相邻兄弟 adjacentA + BB 紧跟在 A 后面:li + li 只选中第 2 个 li
通用兄弟 generalA ~ BB 是 A 后面的所有平级兄弟

「后代」不限层级,「子」只认一层——这是两者唯一的差别,也是嵌套深的时候选错的高发区。

全选:通配选择器

* 选中页面上每一个元素8。它不是拿来写普通样式的,而是做「统一重置」: 后面章节会反复出现的起手式 * { box-sizing: border-box; margin: 0; } 就是它的标准用途。

4. 常见模式:卡片与表单

书里给了两个把上面的件组装起来的模式。

卡片布局:只动「卡片内部的元素」,不影响页面上别处的同类元素9——

.card { border: 1px solid #ccc; }
.card h2 { margin-bottom: 10px; }
.card p { font-size: 14px; }

.card p 是「后代」的用法:只选中卡片里的段落。它对应的真实界面就是你现在读的这种 「带边框的小面板」。

表单状态反馈:用伪类给用户即时的视觉答复10——

input:invalid { border-color: red; }   /* 内容不合规则 → 红框 */
input:focus   { outline: 2px solid blue; }  /* 选中 → 蓝圈 */

这两行能成立,靠的是浏览器自动跟踪「这个输入框当前合不合规则、有没有被选中」—— 不用写一行 JavaScript。

5. 作者的判断与证据

  • 「始终用能完成工作的最简单的选择器」——本章的立场句,断言式,无论证11。 支撑它的理由分散在本章各处:写长了「处理起来更慢」、ID 太「强」后面难覆盖。
  • 「避免用 ID 做样式」——断言,理由(特异性高难覆盖)到第 3 章才兑现12。
  • 「Over-selecting:div.container ul li a 通常没必要,.container a 就够」——经验断言, 与「最简单选择器」立场同源13。

6. 边界与局限

  • 这一章的伪类清单只是最常用的五个,没提 :focus-visible、:checked、:root 等 (后两个在后面的章节里零星出现)。
  • 组合器没提「列组合」(|| 表格列)这类生僻成员——速查书只做常用面。
  • 完全没提 :has()——2023 年起各大浏览器已支持的选择器(选中「包含某元素的元素」), 成书时(2026 年 2 月)它早已可用,本书未收,是其「现代」口径的一处缺口。

判断(我们的,不是书里的): 本章「最简单选择器」的立场比很多同类书讲得早也讲得硬, 值得作为第一原则记住——它的另一面是第 22 章的 BEM 命名法:当「简单」与「不撞名」冲突时, 现代工程的答案是给元素起好类名,而不是把选择器写长。 如果错,会错在: 在第三方内容注入的场景(富文本、用户评论)里,你没有类名可用, 只能写长的后代选择器——「最简单」原则在那类场景要让位于「没得选」。

7. 可带走的

  1. 六类选法:标签、类、ID、属性、状态(伪类 :)、部位(伪元素 ::),再加关系(组合器)和全选(*)。
  2. 类是主力:可复用、可叠加;ID 留给页面唯一元素,样式里尽量别用112。
  3. .box ≠ .Box,类名区分大小写2;div.active ≠ div .active,一个空格就是两层关系3。
  4. > 只认直接孩子,空格不限层级——嵌套深时选错的头号原因。
  5. 单冒号管状态,双冒号管部位,别混7。
  6. 伪类让元素「随用户操作换脸」,伪元素能凭空加内容(::after + content),星号必填标记就是它的作品6。
  7. 写长选择器之前先停一下:能不能加个类名解决?

8. 原文地图

主题原书章原文位置
六类选择器总览Chapter 2: Selectors Referencetext/03-ch01-1-chapter-overview.txt:11(搜「Basic selectors」)
类名/ID 区分大小写同上text/03-ch01-1-chapter-overview.txt:23(搜「not the same as .Box」)
分组选择器(逗号)同上text/03-ch01-1-chapter-overview.txt:25(搜「Grouping Selectors」)
选择器有不同的「分量」同上text/03-ch01-1-chapter-overview.txt:27(搜「weights」)
属性选择器同上text/03-ch01-1-chapter-overview.txt:74(搜「Attribute Selectors」)
伪类与常用值同上text/03-ch01-1-chapter-overview.txt:87(搜「Pseudo-classes」)
伪元素与常用值同上text/03-ch01-1-chapter-overview.txt:102(搜「Pseudo-elements」)
四种组合器表同上text/03-ch01-1-chapter-overview.txt:117(搜「Combinators」)
空格之差的坑同上text/03-ch01-1-chapter-overview.txt:159(搜「Space Matters」)
单双冒号之辨同上text/03-ch01-1-chapter-overview.txt:157(搜「Confusing」)
卡片模式同上text/03-ch01-1-chapter-overview.txt:138(搜「Card」)
表单状态反馈同上text/03-ch01-1-chapter-overview.txt:145(搜「Form Validation」)
最简单选择器立场同上text/03-ch01-1-chapter-overview.txt:171(搜「simplest selector」)

Footnotes

  1. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:72,搜「unique within a single HTML page」)。原文:「Use IDs sparingly; they must be unique within a single HTML page.」 ↩ ↩2

  2. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:23,搜「not the same as .Box」)。原文:「Class and ID selectors are case-sensitive (e.g., .box is not the same as .Box).」 ↩ ↩2

  3. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:159,搜「Space Matters」)。原文:div.active(无空格)选中带 active 类的 <div>;div .active(有空格)选中 <div> 内部任何带 active 类的元素。 ↩ ↩2

  4. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:74,搜「Attribute Selectors」)。原文语法:[attribute] 或 [attribute="value"];例子 input[type="text"]、a[target="_blank"]。 ↩

  5. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:87,搜「Pseudo-classes」)。原文列出的常用值::hover, :focus, :first-child, :nth-child(n), :not()。 ↩

  6. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:102,搜「Pseudo-elements」;:113 搜「required」)。原文例子:.required::after { content: " *"; color: red; },输出解释为「Elements with the "required" class will show a red asterisk after their content.」 ↩ ↩2

  7. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:157,搜「Confusing」)。原文:「Modern CSS uses single colon : for pseudo-classes (states) and double colon :: for pseudo-elements (parts).」 ↩ ↩2

  8. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:31,搜「Universal Selector」)。原文:「Targets every single element on the page.」 ↩

  9. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:138,搜「Card」)。原文:「Using descendant selectors to style elements inside a specific container without affecting the rest of the page.」 ↩

  10. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:145,搜「Form Validation」)。原文:「Using pseudo-classes to provide visual feedback to users.」 ↩

  11. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:171,搜「simplest selector」)。原文:「Always aim for the simplest selector that gets the job done.」 ↩

  12. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:155,搜「ID Overuse」)。原文:「Avoid using IDs for styling. They are too "strong" (high specificity), making them hard to override later. Use classes instead.」 ↩ ↩2

  13. 出处:「Chapter 2: Selectors Reference」(text/03-ch01-1-chapter-overview.txt:153,搜「Over-selecting」)。原文:「Writing div.container ul li a is often unnecessary. .container a is usually enough and faster to process.」 ↩

On this page