pin_drop当前位置:知识文库 ❯ 图文
CSS伪类详解:hover、focus、nth-child等常用伪类应用指南
一、教程简介
CSS 伪类是添加到选择器末尾的关键字,用于指定元素的特殊状态。通过伪类,我们可以根据用户的交互行为(如悬停、聚焦)、元素在文档中的位置(如第一个子元素、第n个子元素)等条件来应用样式,无需修改 HTML 结构或使用 JavaScript。本教程将系统讲解最常用的 CSS 伪类及其在实际开发中的应用。
二、核心概念
伪类分类
伪类与伪元素的区别
-
伪类:单冒号
:,表示元素的特殊状态,如:hover -
伪元素:双冒号
::,表示元素的特定部分,如::before
三、语法与用法
交互伪类
代码示例
/* 鼠标悬停 */
a:hover { color: red; }
/* 鼠标按下 */
button:active { transform: scale(0.95); }
/* 获得焦点 */
input:focus { border-color: blue; }
/* 子元素获焦点(父元素样式) */
.form-group:focus-within { border-color: blue; }
/* 链接状态顺序:LVHA */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; }
a:active { color: orange; }结构伪类
代码示例
/* 第一个子元素 */
li:first-child { font-weight: bold; }
/* 最后一个子元素 */
li:last-child { border-bottom: none; }
/* 第n个子元素 */
li:nth-child(2) { } /* 第2个 */
li:nth-child(odd) { } /* 奇数位 */
li:nth-child(even) { } /* 偶数位 */
li:nth-child(3n) { } /* 每3个 */
li:nth-child(3n+1) { } /* 1,4,7... */
li:nth-child(-n+3) { } /* 前3个 */
/* 唯一子元素 */
p:only-child { }表单伪类
代码示例
input:checked { }
input:disabled { opacity: 0.5; }
input:valid { border-color: green; }
input:invalid { border-color: red; }
input:required { }
input:placeholder-shown { }否定伪类
代码示例
/* 排除匹配 */
li:not(:last-child) { margin-bottom: 10px; }
input:not(:disabled) { cursor: pointer; }四、代码示例
示例1:交互伪类
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>交互伪类演示</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Microsoft YaHei', sans-serif; background: #f5f5f5; color: #333; padding: 30px; }
h1 { text-align: center; color: #2c3e50; margin-bottom: 30px; }
.container { max-width: 800px; margin: 0 auto; }
.section { background: white; padding: 25px; border-radius: 10px; margin-bottom: 25px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
.section h2 { color: #34495e; font-size: 18px; margin-bottom: 15px; padding-bottom: 8px; border-bottom: 2px solid #ecf0f1; }
/* :hover 按钮 */
.btn { display: inline-block; padding: 10px 24px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; margin: 5px; }
.btn-primary { background: #3498db; color: white; }
.btn-primary:hover { background: #2980b9; transform: translateY(-2px); box-shadow: 0 4px 12px rgba(52,152,219,0.4); }
.btn-primary:active { transform: translateY(0); box-shadow: none; }
.btn-outline { background: transparent; border: 2px solid #3498db; color: #3498db; }
.btn-outline:hover { background: #3498db; color: white; }
/* :focus 输入框 */
.form-group { margin-bottom: 15px; }
.form-group label { display: block; margin-bottom: 5px; font-size: 14px; color: #555; }
.form-input { width: 100%; padding: 10px 12px; border: 2px solid #e0e0e0; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.3s, box-shadow 0.3s; }
.form-input:focus { border-color: #3498db; box-shadow: 0 0 0 3px rgba(52,152,219,0.15); }
/* :focus-within */
.focus-within-box { padding: 20px; border: 2px solid #e0e0e0; border-radius: 8px; transition: border-color 0.3s, box-shadow 0.3s; }
.focus-within-box:focus-within { border-color: #27ae60; box-shadow: 0 0 0 3px rgba(39,174,96,0.15); }
/* :hover 卡片 */
.hover-card { background: white; border: 1px solid #eee; border-radius: 10px; padding: 20px; transition: all 0.3s; cursor: pointer; }
.hover-card:hover { border-color: #3498db; box-shadow: 0 8px 25px rgba(0,0,0,0.1); transform: translateY(-4px); }
.hover-card h3 { color: #2c3e50; margin-bottom: 8px; }
.hover-card p { color: #7f8c8d; font-size: 14px; }
.hover-card .arrow { float: right; color: #3498db; opacity: 0; transition: opacity 0.3s, transform 0.3s; }
.hover-card:hover .arrow { opacity: 1; transform: translateX(5px); }
</style>
</head>
<body>
<div class="container">
<h1>交互伪类演示</h1>
<div class="section">
<h2>:hover 和 :active</h2>
<button class="btn btn-primary">悬停查看效果</button>
<button class="btn btn-outline">描边按钮</button>
</div>
<div class="section">
<h2>:focus</h2>
<div class="form-group"><label>用户名</label><input type="text" class="form-input" placeholder="点击输入框查看:focus效果"></div>
</div>
<div class="section">
<h2>:focus-within</h2>
<div class="focus-within-box">
<label style="font-size: 14px; color: #555;">当任意子元素获焦点时,容器边框变绿</label>
<input type="text" class="form-input" placeholder="点击这里" style="margin-top: 8px;">
</div>
</div>
<div class="section">
<h2>:hover 卡片交互</h2>
<div class="hover-card">
<span class="arrow">→</span>
<h3>鼠标悬停查看效果</h3>
<p>卡片上移、阴影加深、箭头出现</p>
</div>
</div>
</div>
</body>
</html>示例2:结构伪类
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>结构伪类演示</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Microsoft YaHei', sans-serif; background: #1a1a2e; color: #eee; padding: 30px; }
h1 { text-align: center; color: #64ffda; margin-bottom: 30px; }
.container { max-width: 900px; margin: 0 auto; }
.section { background: #16213e; padding: 25px; border-radius: 10px; margin-bottom: 25px; border: 1px solid #2a2a4a; }
.section h2 { color: #64ffda; font-size: 18px; margin-bottom: 15px; }
/* 列表样式 */
.styled-list { list-style: none; padding: 0; }
.styled-list li { padding: 12px 15px; margin-bottom: 4px; border-radius: 4px; font-size: 14px; transition: background 0.2s; }
.styled-list li:hover { background: rgba(100,255,218,0.1); }
.styled-list li:first-child { border-left: 3px solid #64ffda; font-weight: bold; }
.styled-list li:last-child { border-left: 3px solid #e74c3c; }
.styled-list li:nth-child(odd) { background: rgba(255,255,255,0.03); }
.styled-list li:nth-child(even) { background: rgba(255,255,255,0.06); }
/* 表格斑马纹 */
.data-table { width: 100%; border-collapse: collapse; }
.data-table th, .data-table td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #2a2a4a; font-size: 14px; }
.data-table th { background: #0f3460; color: #64ffda; }
.data-table tr:nth-child(even) { background: rgba(255,255,255,0.03); }
.data-table tr:hover { background: rgba(100,255,218,0.08); }
/* :not() 排除 */
.nav-tabs { display: flex; gap: 0; list-style: none; padding: 0; }
.nav-tabs li { padding: 10px 20px; background: #0f3460; cursor: pointer; transition: background 0.3s; font-size: 14px; }
.nav-tabs li:not(:last-child) { border-right: 1px solid #2a2a4a; }
.nav-tabs li:hover { background: #1a4a7a; }
.nav-tabs li.active { background: #64ffda; color: #1a1a2e; font-weight: bold; }
/* 网格 nth-child */
.color-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; }
.color-box { height: 50px; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: bold; }
.color-box:nth-child(3n+1) { background: #e74c3c; color: white; }
.color-box:nth-child(3n+2) { background: #3498db; color: white; }
.color-box:nth-child(3n) { background: #27ae60; color: white; }
</style>
</head>
<body>
<div class="container">
<h1>结构伪类演示</h1>
<div class="section">
<h2>:first-child / :last-child / :nth-child()</h2>
<ul class="styled-list">
<li>第一项 - :first-child 绿色左边框</li>
<li>第二项 - 偶数行背景</li>
<li>第三项 - 奇数行背景</li>
<li>第四项 - 偶数行背景</li>
<li>最后一项 - :last-child 红色左边框</li>
</ul>
</div>
<div class="section">
<h2>表格斑马纹 - :nth-child(even/odd)</h2>
<table class="data-table">
<thead><tr><th>姓名</th><th>部门</th><th>状态</th></tr></thead>
<tbody>
<tr><td>张三</td><td>技术部</td><td>在职</td></tr>
<tr><td>李四</td><td>产品部</td><td>在职</td></tr>
<tr><td>王五</td><td>设计部</td><td>休假</td></tr>
<tr><td>赵六</td><td>市场部</td><td>在职</td></tr>
</tbody>
</table>
</div>
<div class="section">
<h2>:not() 排除伪类</h2>
<ul class="nav-tabs">
<li class="active">首页</li>
<li>产品</li>
<li>方案</li>
<li>关于</li>
</ul>
<p style="font-size: 13px; color: #a0a0a0; margin-top: 10px;">li:not(:last-child) 排除最后一项的右边框</p>
</div>
<div class="section">
<h2>:nth-child(3n+1) 循环配色</h2>
<div class="color-grid">
<div class="color-box">1</div><div class="color-box">2</div><div class="color-box">3</div>
<div class="color-box">4</div><div class="color-box">5</div><div class="color-box">6</div>
<div class="color-box">7</div><div class="color-box">8</div><div class="color-box">9</div>
<div class="color-box">10</div><div class="color-box">11</div><div class="color-box">12</div>
</div>
</div>
</div>
</body>
</html>示例3:表单伪类
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表单伪类演示</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Microsoft YaHei', sans-serif; background: #f5f5f5; color: #333; padding: 30px; }
h1 { text-align: center; color: #2c3e50; margin-bottom: 30px; }
.container { max-width: 600px; margin: 0 auto; }
.section { background: white; padding: 25px; border-radius: 10px; margin-bottom: 25px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
.section h2 { color: #34495e; font-size: 18px; margin-bottom: 15px; padding-bottom: 8px; border-bottom: 2px solid #ecf0f1; }
.form-group { margin-bottom: 18px; }
.form-group label { display: block; margin-bottom: 6px; font-size: 14px; color: #555; }
.form-input { width: 100%; padding: 10px 12px; border: 2px solid #e0e0e0; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.3s; }
.form-input:focus { border-color: #3498db; }
.form-input:valid { border-color: #27ae60; }
.form-input:invalid:not(:placeholder-shown) { border-color: #e74c3c; }
.form-input:disabled { background: #f0f0f0; cursor: not-allowed; opacity: 0.6; }
.form-input:read-only { background: #f8f9fa; }
.form-input:required { border-left: 3px solid #e74c3c; }
.form-input:optional { border-left: 3px solid #27ae60; }
/* 自定义复选框 */
.custom-checkbox { display: flex; align-items: center; gap: 10px; cursor: pointer; font-size: 14px; }
.custom-checkbox input[type="checkbox"] { width: 20px; height: 20px; accent-color: #3498db; cursor: pointer; }
.hint { font-size: 12px; color: #7f8c8d; margin-top: 4px; }
.hint-error { color: #e74c3c; }
.hint-success { color: #27ae60; }
</style>
</head>
<body>
<div class="container">
<h1>表单伪类演示</h1>
<div class="section">
<h2>:valid / :invalid</h2>
<div class="form-group">
<label>邮箱(:valid/:invalid)</label>
<input type="email" class="form-input" placeholder="输入有效邮箱变绿,无效变红" required>
<p class="hint">输入内容后,有效邮箱边框变绿,无效邮箱边框变红</p>
</div>
</div>
<div class="section">
<h2>:required / :optional</h2>
<div class="form-group">
<label>必填字段(:required)</label>
<input type="text" class="form-input" placeholder="红色左边框表示必填" required>
</div>
<div class="form-group">
<label>可选字段(:optional)</label>
<input type="text" class="form-input" placeholder="绿色左边框表示可选">
</div>
</div>
<div class="section">
<h2>:disabled / :read-only</h2>
<div class="form-group">
<label>禁用字段(:disabled)</label>
<input type="text" class="form-input" value="不可编辑" disabled>
</div>
<div class="form-group">
<label>只读字段(:read-only)</label>
<input type="text" class="form-input" value="只读内容" readonly>
</div>
</div>
</div>
</body>
</html>五、浏览器兼容性
六、注意事项与最佳实践
注意事项
-
LVHA顺序:链接伪类应按
:link→:visited→:hover→:active顺序书写 -
:hover在移动端:触摸设备上
:hover可能表现异常,需用@media (hover: hover)区分 -
:nth-child计数:从1开始计数,不是0
-
:first-child条件:元素必须是父元素的第一个子元素,无论类型
-
:focus-visible:比
:focus更适合键盘焦点样式,避免鼠标点击时显示焦点环
最佳实践
-
交互反馈:所有可交互元素都应有
:hover和:focus状态 -
斑马纹表格:使用
:nth-child(even/odd)实现交替行背景 -
列表间距:使用
li:not(:last-child) { margin-bottom }避免最后一项多余间距 -
表单验证:使用
:valid/:invalid提供即时视觉反馈 -
无障碍:确保
:focus样式清晰可见,不要使用outline: none除非提供替代方案
七、代码规范示例
不推荐的写法
代码示例
/* 不推荐:移除焦点样式 */
*:focus { outline: none; }
/* 不推荐::hover没有过渡 */
.btn:hover { background: red; }
/* 颜色突变,体验差 */
/* 不推荐:错误的LVHA顺序 */
a:hover { color: red; }
a:visited { color: purple; }
/* :visited会覆盖:hover */推荐的写法
代码示例
/* 推荐:保留焦点样式 */
:focus-visible { outline: 2px solid #3498db; outline-offset: 2px; }
/* 推荐:添加过渡 */
.btn { transition: background 0.3s; }
.btn:hover { background: #2980b9; }
/* 推荐:正确的LVHA顺序 */
a:link { color: #3498db; }
a:visited { color: #9b59b6; }
a:hover { color: #e74c3c; }
a:active { color: #f39c12; }八、常见问题与解决方案
常见问题
:first-child不生效怎么办?
原因:元素前面有其他类型的子元素(如文本节点、注释)。
解决方案:使用 :first-of-type 匹配同类型中的第一个。
:nth-child匹配了意外元素怎么办?
原因::nth-child 计算所有类型的子元素,不区分元素类型。
解决方案:使用 :nth-of-type() 仅计算同类型元素。
移动端:hover粘滞如何处理?
原因:触摸设备上 :hover 状态可能持续到下次触摸。
解决方案:使用 @media (hover: hover) 仅在支持悬停的设备上应用 :hover 样式。
九、总结
CSS 伪类是样式化元素特殊状态的强大工具。交互伪类(:hover、:focus、:active)提供用户反馈,结构伪类(:first-child、:nth-child())实现基于位置的样式,表单伪类(:valid、:disabled)增强表单体验。掌握伪类的语法和优先级规则,可以大幅减少对 JavaScript 的依赖,用纯 CSS 实现丰富的交互效果。核心原则是:交互必有反馈、结构善用伪类、表单即时验证。
本文涉及AI创作
内容由AI创作,请仔细甄别