第三章:精准定位:从基础到高级选择器

第三章:精准定位:从基础到高级选择器

摘要: 本章将是 CSS 选择器的完全指南。我们将从回顾基础选择器开始,深入学习如何通过组合、属性、状态和结构来构建强大的选择器,实现对任何元素的精准定位。本章的重点是伪类和伪元素,它们是实现交互效果和高级 UI 设计的关键。最后,我们将通过一个实战案例,将所学知识融会贯通。


在本章中,我们将解锁 CSS 的“精确制导”能力:

  1. 首先,我们将快速 回顾基础与组合选择器,巩固已有知识。
  2. 接着,我们将学习 属性选择器,根据元素的“身份证”信息来定位它。
  3. 然后,我们将深入本章的第一个核心——伪类选择器,让页面能够响应用户的交互和状态。
  4. 之后,我们将掌握第二个核心——伪元素选择器,学会在不改变 HTML 的情况下创建和装饰虚拟元素。
  5. 最后,我们将进入 实战环节,综合运用所学知识,构建一个带分隔线的导航菜单效果。

3.1. 基础与组合选择器回顾

上一章我们对核心选择器有了一定认识,现在来快速回顾。

基础选择器

  • 标签选择器:如 p,能选中页面中所有 <p> 标签元素,方便统一设置某类标签样式。
  • 类选择器:像 .container,可选中所有 class 属性值为“container”的元素,在日常样式设置中使用频率高,能对不同标签应用相同样式。
  • ID 选择器#main,用于选中唯一 ID 为“main”的元素,一个页面中 ID 应唯一,常配合 JavaScript 操作特定元素。
  • 通配符选择器*,会选中页面所有元素,不过使用时要谨慎,以免影响性能。

组合选择器

  • 后代选择器nav a,能选中 <nav> 元素内部所有 <a> 元素,不管嵌套多深,方便对特定容器内元素设置样式。
  • 子元素选择器ul > li,仅选中 <ul> 元素的直接子元素 <li>,不会选中更深层级的 <li>,精准控制直接子元素。
  • 相邻兄弟选择器h1 + p,选中紧跟在 <h1> 元素后的第一个 <p> 元素,当需要为特定元素后的紧邻元素设置样式时很有用。
  • 通用兄弟选择器h1 ~ p,选中在 <h1> 元素之后的所有 <p> 元素,只要在源文档顺序上在 <h1> 之后即可,不要求紧邻 。

3.2. 属性选择器:根据标签属性定位

属性选择器允许我们根据 HTML 元素的属性(如 href, target, type)及其值来应用样式,这在处理表单或特定链接时非常有用,如果这里您学过正则表达式,那么理解起来会十分轻松,我们只需要记住 ^ 代表开头,$ 代表全选,* 代表包含即可

写法说明示例
[attr]选中拥有 attr 属性的元素a[title]
[attr=val]选中 attr 属性值 完全等于 val 的元素a[target=_blank]
[attr^=val]选中 attr 属性值以 val 开头 的元素a[href^="https"]
[attr$=val]选中 attr 属性值以 val 结尾 的元素a[href$=".pdf"]
[attr*=val]选中 attr 属性值 包含 val 的元素a[href*="google"]

痛点背景: 你希望为网站上所有指向外部网站的链接(在新窗口打开)和所有指向 PDF 文件的链接自动添加一个特殊的小图标,以提示用户。

解决方案: 我们可以完美地利用属性选择器来实现这个需求,而无需手动为这些链接添加特定的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<style>
a {
margin-right: 20px;
color: #3498db;
}
/* 选中所有在新窗口打开的链接 */
a[target="_blank"] {
font-weight: bold;
}
/* 选中所有链接到 https 网站的链接 */
a[href^="https"] {
font-style: italic;
}
/* 选中所有链接到 .pdf 文件的链接 */
a[href$=".pdf"] {
color: green;
}
</style>

<a href="/about">公司简介 (内部链接)</a>
<a href="https://google.com" target="_blank">Google (外部链接)</a>
<a href="files/report.pdf">下载报告 (PDF)</a>

3.3. 伪类选择器:响应用户交互与状态

伪类是 CSS 的一大特色,它允许我们为元素的某些 特殊状态(如鼠标悬停、链接被访问)或 特殊位置(如第一个子元素)应用样式。伪类以单个冒号 : 开头。

3.3.1. 动态与链接伪类

这些伪类与用户的行为和浏览历史相关,是实现 UI 交互效果的基础。

伪类描述
:hover(最常用) 鼠标指针悬停在元素上时。
:active元素被用户激活时(如鼠标按下未松开)。
:focus元素获得焦点时(如通过 Tab 键选中的输入框)。
:link特指 <a> 标签,匹配未被访问过的链接。
:visited特指 <a> 标签,匹配已被访问过的链接。

LVHA 顺序: 在为链接定义样式时,建议遵循 :link -> :visited -> :hover -> :active 的书写顺序。这是一个经典的记忆法则 “LoVe HAte”,可以确保 :hover:active 的效果不会被 :link:visited 覆盖掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<style>
.btn {
display: inline-block;
padding: 10px 20px;
background-color: #3498db;
color: white;
text-decoration: none;
border-radius: 5px;
transition: all 0.3s ease; /* 添加一个平滑过渡效果 */
}
/* 鼠标悬停时改变背景色 */
.btn:hover {
background-color: #2980b9;
}
/* 鼠标按下时添加内阴影 */
.btn:active {
box-shadow: inset 0 3px 5px rgba(0,0,0,0.2);
}
</style>

<a href="#" class="btn">一个交互式按钮</a>

3.3.2. 结构性伪类

这类伪类根据元素在 DOM 树中的位置或结构关系来选择元素,非常强大。

伪类描述
:first-child匹配作为其父元素的 第一个 子元素的元素。
:last-child匹配作为其父元素的 最后一个 子元素的元素。
:nth-child(n)匹配作为其父元素的 第 n 个 子元素的元素。
:nth-of-type(n)匹配作为其父元素的 第 n 个同类型 的元素。
:not(selector)匹配不符合 selector 的所有元素。

n 可以是数字、关键字 (odd(奇数), even(偶数)) 或公式 (3n+1)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<style>
/* 匹配第一个div */
div:first-child { color: red; }
/* 匹配最后一个div */
div:last-child { color: blue; }
/* 精确匹配第二个div */
div:nth-child(2) { color: green; }
/* 匹配第一个p */
p:nth-of-type(1) { font-weight: bold; }
/* 匹配不是special类的div */
div:not(.special) { background: yellow; }
</style>
</head>
<body>
<div>第一个div</div>
<div class="special">第二个div</div>
<div>第三个div</div>
<p>段落1</p>
<p>段落2</p>
</body>
</html>
: nth-child vs : nth-of-type
2025-08-25

li:nth-child(2)li:nth-of-type(2) 有什么区别?它们看起来很像。

P
Prorise

这是一个非常关键的区别!

P
Prorise

li:nth-child(2) 的意思是:“找到一个元素,它必须是其父元素的 第 2 个 孩子,并且它自己 恰好 还是一个 <li> 元素”。如果第 2 个孩子是 <div>,那么这个选择器就什么也选不中。

P
Prorise

li:nth-of-type(2) 的意思是:“在其父元素的所有 <li> 孩子中,找到 第 2 个 <li>”。它会忽略其他类型的兄弟元素。

P
Prorise

简单说,nth-child 是“先定位,再看类型”,而 nth-of-type 是“先按类型分组,再定位”。在有混合类型兄弟元素的场景下,nth-of-type 通常更可靠。

示例: 实现一个“斑马条纹”表格,并为第一行和最后一行添加特殊样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<style>
/* 选中所有<ul>下的<li>标签 */
ul li {
/* 去除li标签的默认样式 */
list-style: none;
padding: 10px;
border-bottom: 1px solid #eee;
}

/* 选中第一个<ul>下的<li>标签 */
ul li:first-child {
font-weight: bold;
color: #2980b9;
border-top: 2px solid #2980b9;
}

/* 选中最后一个li标签 */
ul li:last-child {
border-bottom: 2px solid #2980b9;
}

/* 选中所有的奇数行实现斑马条纹 */
ul li:nth-child(odd) {
background-color: #f0f0f0;
}

/* 选中除了有 .highlight 类的所有 li */
ul li:not(.highlight) {
/* 添加过渡效果 */
transition: background-color 0.3s;
}

ul li:hover:not(.highlight) {
background-color: #f0f0f0;
}

.highlight {
background-color: #2980b9;
color: #fff;
}
</style>

<ul>
<li>第一项</li>
<li class="highlight">第二项 (高亮)</li>
<li>第三项</li>
<li>第四项</li>
<li>第五项</li>
</ul>

3.4. 伪元素选择器:创建虚拟元素

伪元素与伪类不同,它不是为已有元素添加特殊状态,而是 创建出一个在 DOM 树中不存在的虚拟元素,并为其添加样式。伪元素在现代 CSS 中以双冒号 :: 开头,以区别于伪类。

伪元素描述
::before在选中元素内容的 前面 插入一个虚拟元素。
::after在选中元素内容的 后面 插入一个虚拟元素。
::first-letter(少用)选中块级元素内容的第一个字母。
::first-line(少用)选中块级元素内容的第一行。
::selection(少用)匹配用户鼠标选中的文本部分。
::placeholder(少用)匹配输入框的占位提示文本。

关键规则: ::before::after 创建的虚拟元素默认是 行内元素。它们必须包含 content 属性(即使是 content: '';)才能生效。

示例: 使用 ::before::after 为引用文本添加装饰性的引号,并自定义选中文本的样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<style>
blockquote {
font-size: 1.2em;
font-style: italic;
color: #555;
background: #f9f9f9;
border-left: 5px solid #ccc;
padding: 10px 20px;
margin: 20px 0;
}
/* 在引用文本前添加一个左引号 */
blockquote::before {
content: "“";
font-size: 2em;
color: #ccc;
line-height: 0.1em;
margin-right: 0.1em;
vertical-align: -0.4em;
}
/* 在引用文本后添加一个右引号 */
blockquote::after {
content: "”";
font-size: 2em;
color: #ccc;
line-height: 0.1em;
margin-left: 0.1em;
vertical-align: -0.45em;
}
/* 自定义鼠标选中文本的样式 */
blockquote::selection {
background-color: #2980b9;
color: white;
}
</style>

<blockquote>CSS 的强大之处在于其看似简单却蕴含无限可能的组合性。</blockquote>

3.5. 实战应用:构建一个带分隔线的导航菜单 (修正版)

目标: 创建一个如下图所示的,干净、稳定、带分隔线的水平导航菜单。

img

动手思路

  1. HTML 结构: 使用 <ul><li> 构建导航的语义化骨架。
  2. 水平布局: 为 <li> 设置 display: inline-block; 实现水平排列,并移除 <ul> 的默认列表样式。
  3. 交互样式: 为 <li> 添加 :hover 伪类以改变背景色,并为 <a> 设置 padding 和基础样式。
  4. 添加分隔线: 为每个 <li> 添加 border-right 来创建分隔线,这比使用伪元素更稳定。
  5. 移除末尾分隔线: 使用 :last-child 伪类,选中最后一个 <li>,并将其 border-right 移除。

Html 结构如下:

1
2
3
4
5
6
7
8
<nav class="main-nav">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">产品中心</a></li>
<li><a href="#">关于我们</a></li>
<li><a href="#">联系我们</a></li>
</ul>
</nav>

CSS 实现与解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<style>
/* 容器基础样式 */
.main-nav {
text-align: center;
background-color: white;
border-radius: 5px;
}

.main-nav ul {
list-style: none;
padding: 0;
margin: 0;
}

.main-nav li {
/* 让他变为行内块即可并排起来 */
display: inline-block;
font-size: 16px;
/* 在子元素上恢复字体大小 */

/* 核心思路:使用 border-right 作为分隔线,更稳定 */
border-right: 1px solid #ccc;
}

.main-nav a {
display: block;
padding: 15px 20px;
color: #333;
text-decoration: none;
transition: background-color 0.3s;
}

.main-nav li:hover {
background-color: #ddd;
}

.main-nav li:last-child {
border-right: none;
}
</style>

3.6. 本章核心速查总结

分类关键项核心描述
属性选择器[attr^=val], [attr$=val]根据属性值的 开头结尾 进行匹配,常用于链接样式。
动态伪类:hover, :focus, :active实现 UI 交互效果的三剑客。
结构性伪类:nth-child(n)先找第 n 个孩子,再判断类型是否匹配。
p:nth-of-type(n)(推荐) 先按 p 类型分组,再找该类型的第 n 个。
:not(selector)排除特定元素,非常实用。
伪元素::before, ::after(核心) 创建虚拟的行内元素,必须包含 content 属性。
::selection自定义用户用鼠标选中文本时的背景和颜色。
::placeholder自定义输入框占位文本的样式。