CSS 伪类详解:UI 伪类与结构化伪类的用法与实战
CSS 伪类(Pseudo-class)是一种特殊的选择符,用于选择处于特定状态或具有特定结构关系的元素—— 它们无需在 HTML 中添加实际的 class 或 id,而是通过元素的 “动态状态”(如鼠标悬停)或 “结构位置”(如列表第 3 项)来定位元素。伪类极大地扩展了 CSS 的选择能力,是实现交互效果和结构化样式的核心工具。从 “核心概念→分类详解→实战场景→注意事项” 四个维度,全面讲解伪类的使用方法与进阶技巧。
伪类核心概念
1. 伪类的语法
伪类以冒号 : 开头,紧跟伪类名称,语法格式如下:
1 2 3 4 5 6 7 8 9
| 选择符:伪类名称 { 属性: 值; }
a:hover { color: red; }
|
2. 伪类的核心特点
- 无实际 class:伪类不依赖 HTML 中的
class 属性,而是基于元素的 “状态” 或 “结构” 动态生效;
- 动态性:UI 伪类(如
:hover)会随用户操作(如鼠标移动)实时切换样式;
- 结构性:结构化伪类(如
:nth-child)仅依赖 HTML 结构(如元素在父容器中的位置),与用户操作无关;
- 可叠加使用:多个伪类可叠加(如
a:link:hover,表示 “未点击的链接被悬停时”)。
UI 伪类:基于元素状态的样式
UI 伪类(UI Pseudo-classes)用于选择处于特定交互状态的元素,核心场景是响应用户操作(如点击、悬停、聚焦),最典型的应用是链接样式控制。
1. 链接相关的 UI 伪类
链接(<a> 标签)是 UI 伪类最常用的场景,4 个伪类分别对应链接的不同生命周期状态,必须按固定顺序书写(link → visited → hover → active),否则样式可能失效。
| 伪类名称 |
作用描述 |
适用元素 |
示例效果 |
:link |
选择未被点击过的链接(默认状态) |
<a>(必须有 href) |
未点击的链接为蓝色(默认) |
:visited |
选择已被点击过的链接(浏览器记录过访问历史) |
<a>(必须有 href) |
已点击的链接为紫色(默认) |
:hover |
选择鼠标正悬停在上面的元素 |
所有元素(常用 <a>、按钮) |
鼠标悬停时链接变红色 |
:active |
选择正在被点击的元素(鼠标按下但未松开的瞬间) |
所有元素(常用 <a>、按钮) |
点击时链接变深红色 |
示例:链接样式的完整实现(按顺序书写)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| a:link { color: #2c7be5; text-decoration: none; }
a:visited { color: #868e96; }
a:hover { color: #195fc6; text-decoration: underline; }
a:active { color: #0f3fa8; }
|
关键注意事项:
顺序规则:link → visited → hover → active(记忆口诀:LVHA),因为后定义的样式会覆盖先定义的,若顺序错误(如 hover 在 visited 前),visited 样式会覆盖 hover;
:visited 的限制:出于隐私保护,浏览器限制 :visited 可设置的样式(仅支持 color、background-color、border-color 等,无法设置 background-image、box-shadow 等);
非链接元素的应用:hover和active可用于按钮、卡片等元素,实现交互效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .btn { padding: 8px 16px; background-color: #2c7be5; color: white; border: none; border-radius: 4px; } .btn:hover { background-color: #195fc6; } .btn:active { background-color: #0f3fa8; }
|
2. 表单相关的 UI 伪类
表单元素(如输入框、复选框)的状态(聚焦、禁用、选中)也可通过 UI 伪类控制,是表单美化的核心工具。
| 伪类名称 |
作用描述 |
适用元素 |
:focus |
选择获得焦点的元素(如输入框被点击、通过 Tab 键选中) |
<input>、<textarea>、<select> |
:disabled |
选择被禁用的元素(HTML 中设置 disabled 属性) |
表单元素(<input>、按钮等) |
:enabled |
选择未被禁用的元素(与 :disabled 相反) |
表单元素 |
:checked |
选择被选中的元素(如复选框、单选按钮) |
<input type="checkbox/radio"> |
:placeholder-shown |
选择占位符(placeholder)可见的输入框(即未输入内容时) |
<input>、<textarea> |
示例:表单元素的伪类样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| input:focus { outline: none; border-color: #2c7be5; box-shadow: 0 0 0 2px rgba(44, 123, 229, 0.2); }
input:disabled { background-color: #f8f9fa; color: #adb5bd; cursor: not-allowed; }
input[type="checkbox"]:checked + span { color: #2c7be5; font-weight: bold; }
input:placeholder-shown { border-color: #ced4da; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div> <label> <input type="checkbox"> <span>同意用户协议</span> </label> </div> <div> <input type="text" placeholder="请输入用户名" class="form-input"> </div> <div> <input type="text" value="禁用的输入框" disabled class="form-input"> </div>
|
结构化伪类:基于元素结构的样式
结构化伪类(Structural Pseudo-classes)用于选择具有特定结构关系的元素(如 “第 3 个列表项”“表格的偶数行”“父元素的第一个子元素”),无需手动为元素添加 class,即可实现结构化样式(如奇偶行交替色、首项特殊样式)。
1. 核心结构化伪类::nth-child()
:nth-child(n) 是最常用的结构化伪类,用于选择 “父元素的第 n 个子元素”,支持多种取值方式,灵活度极高。
语法与取值
1 2 3 4
| 父元素 选择符:nth-child(取值) { 属性: 值; }
|
| 取值类型 |
示例 |
作用描述 |
| 具体数字 |
:nth-child(3) |
选择第 3 个子元素(从 1 开始计数) |
even/odd |
:nth-child(even) |
even:选择偶数位置的子元素(2、4、6…);odd:选择奇数位置的子元素(1、3、5…) |
公式(an+b) |
:nth-child(2n+1) |
n 从 0 开始递增,计算结果为元素位置(如 2n+1 等价于 odd,2n 等价于 even) |
| 反向计数 |
:nth-child(-n+3) |
选择前 3 个子元素(n=0 时为 3,n=1 时为 2,n=2 时为 1,n=3 时为 0 不生效) |
示例 1:列表奇偶行交替色(表格 / 列表通用)
1 2 3 4 5 6 7 8 9
| ul li:nth-child(odd) { background-color: #f8f9fa; }
ul li:nth-child(even) { background-color: #ffffff; }
|
1 2 3 4 5 6
| <ul style="list-style: none; padding: 0;"> <li style="padding: 8px 12px; border: 1px solid #eee;">列表项 1(奇数行,浅灰背景)</li> <li style="padding: 8px 12px; border: 1px solid #eee;">列表项 2(偶数行,白色背景)</li> <li style="padding: 8px 12px; border: 1px solid #eee;">列表项 3(奇数行,浅灰背景)</li> <li style="padding: 8px 12px; border: 1px solid #eee;">列表项 4(偶数行,白色背景)</li> </ul>
|
示例 2:选择前 3 个列表项
1 2 3 4
| ul li:nth-child(-n+3) { border-left: 3px solid #2c7be5; }
|
2. 其他常用结构化伪类
除了 :nth-child(),还有多个结构化伪类用于定位 “首项、尾项、唯一项” 等特殊位置的元素,进一步简化结构化样式的实现。
| 伪类名称 |
作用描述 |
示例 |
:first-child |
选择父元素的第一个子元素(无论类型) |
ul li:first-child:列表的第一个项 |
:last-child |
选择父元素的最后一个子元素(无论类型) |
ul li:last-child:列表的最后一个项 |
:only-child |
选择父元素中唯一的子元素(若有多个子元素,则不生效) |
div p:only-child:div 中唯一的 p 标签 |
:first-of-type |
选择父元素中同类型的第一个子元素(仅按类型计数,忽略其他类型元素) |
div p:first-of-type:div 中第一个 p 标签(即使前面有 span) |
:last-of-type |
选择父元素中同类型的最后一个子元素 |
div p:last-of-type:div 中最后一个 p 标签 |
:nth-last-child(n) |
从父元素的最后一个子元素开始计数,选择第 n 个元素(反向版 :nth-child) |
ul li:nth-last-child(2):列表的倒数第二个项 |
示例::first-child 与 :first-of-type 的区别
1 2 3 4 5
| <div class="container"> <span>这是一个 span 标签</span> <p>这是第一个 p 标签</p> <p>这是第二个 p 标签</p> </div>
|
1 2 3 4 5 6 7 8 9
| .container :first-child { color: red; }
.container p:first-of-type { color: blue; }
|
效果:
span 标签因是 “第一个子元素” 变红色;
- 第一个
p 标签因是 “同类型第一个” 变蓝色。
实战场景:伪类的综合应用
场景 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 25
| table { width: 100%; border-collapse: collapse; } th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #eee; } th { background-color: #f8f9fa; font-weight: bold; }
tbody tr:nth-child(even) { background-color: #fafbfc; }
tbody tr:hover { background-color: #f1f3f5; cursor: default; }
|
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
| <table> <thead> <tr> <th>姓名</th> <th>年龄</th> <th>性别</th> </tr> </thead> <tbody> <tr> <td>张三</td> <td>25</td> <td>男</td> </tr> <tr> <td>李四</td> <td>30</td> <td>女</td> </tr> <tr> <td>王五</td> <td>28</td> <td>男</td> </tr> </tbody> </table>
|
场景 2:导航菜单的交互效果(UI 伪类组合)
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
| .nav { list-style: none; padding: 0; display: flex; gap: 2px; background-color: #333; } .nav li a { display: block; padding: 12px 20px; color: white; text-decoration: none; }
.nav li a:link { color: white; }
.nav li a:visited { color: white; }
.nav li a:hover, .nav li a.active { background-color: #2c7be5; }
.nav li a:active { background-color: #195fc6; }
|
1 2 3 4 5 6
| <ul class="nav"> <li><a href="#" class="active">首页</a></li> <li><a href="#">产品</a></li> <li><a href="#">新闻</a></li> <li><a href="#">关于我们</a></li> </ul>
|
场景 3:列表首项与尾项特殊样式(结构化伪类)
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
| .feature-list { list-style: none; padding: 0; max-width: 600px; } .feature-list li { padding: 15px; margin: 5px 0; border: 1px solid #eee; border-radius: 4px; }
.feature-list li:first-child { border-top: 3px solid #2c7be5; position: relative; } .feature-list li:first-child::before { content: "★"; color: #2c7be5; position: absolute; right: 15px; top: 15px; }
.feature-list li:last-child { border-bottom: 3px solid #2c7be5; text-align: center; } .feature-list li:last-child button { padding: 8px 16px; background-color: #2c7be5; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
1 2 3 4 5 6
| <ul class="feature-list"> <li>核心功能 1:支持多终端适配</li> <li>核心功能 2:提供完善的 API 接口</li> <li>核心功能 3:支持数据导出与导入</li> <li><button>立即体验</button></li> </ul>
|
常见问题与解决方案
1. :nth-child() 计数不符合预期
1 2 3 4 5
| ul li:nth-child(1) { color: red; }
ul li:nth-of-type(1) { color: red; }
|
2. 链接伪类顺序错误导致样式失效
- 问题现象:
hover 样式不生效,或 visited 样式覆盖 hover;
- 原因:未按
link → visited → hover → active 的顺序书写;
- 解决方案:严格遵循 LVHA 顺序,确保后定义的伪类覆盖前定义的(如
hover 在 visited 后,active 在 hover 后)。
3. :hover 样式在移动设备上无响应
总结与最佳实践
1. 核心总结
- UI 伪类:基于元素的动态状态(如
hover、focus),用于实现交互效果,核心是响应用户操作;
- 结构化伪类:基于元素的结构位置(如
:nth-child、:first-child),用于实现结构化样式,无需手动添加 class;
- 伪类与伪元素的区别:伪类(
:)选择元素的状态或位置,伪元素(::,如 ::before)创建虚拟元素(如添加图标),二者常配合使用(如场景 3 中的 :first-child::before)。
2. 最佳实践
- 链接样式:严格遵循 LVHA 顺序,统一
visited 与 link 的样式差异(避免用户混淆);
- 结构化样式:优先使用
:nth-child()/:nth-of-type() 替代手动添加 class(如 class="odd"/class="even"),减少 HTML 冗余;
- 性能优化:避免在复杂页面(如大量列表)使用过于复杂的结构化伪类(如
:nth-child(3n+2)),可能影响渲染性能;
- 兼容性:现代浏览器均支持大部分伪类(IE 11 支持核心伪类如
:nth-child、:hover),无需额外兼容处理