pin_drop当前位置:知识文库 ❯ 图文

CSS伪类详解:hover、focus、nth-child等常用伪类应用指南

一、教程简介

CSS 伪类是添加到选择器末尾的关键字,用于指定元素的特殊状态。通过伪类,我们可以根据用户的交互行为(如悬停、聚焦)、元素在文档中的位置(如第一个子元素、第n个子元素)等条件来应用样式,无需修改 HTML 结构或使用 JavaScript。本教程将系统讲解最常用的 CSS 伪类及其在实际开发中的应用。

二、核心概念

伪类分类

类别 伪类 说明
交互状态 :hover 鼠标悬停
交互状态 :active 鼠标按下
交互状态 :focus 获得焦点
交互状态 :focus-within 子元素获焦点
交互状态 :visited 已访问链接
结构位置 :first-child 第一个子元素
结构位置 :last-child 最后一个子元素
结构位置 :nth-child() 第n个子元素
结构位置 :only-child 唯一子元素
表单状态 :checked 选中状态
表单状态 :disabled 禁用状态
表单状态 :valid/:invalid 验证状态
否定 :not() 排除匹配

伪类与伪元素的区别

  • 伪类:单冒号 :,表示元素的特殊状态,如 :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>

五、浏览器兼容性

伪类 Chrome Firefox Safari Edge IE
:hover 全部 全部 全部 全部 全部
:focus 全部 全部 全部 全部 全部
:focus-within 60+ 52+ 10.1+ 79+ 不支持
:first-child 全部 全部 全部 全部 7+
:last-child 全部 全部 全部 全部 9+
:nth-child() 全部 全部 全部 全部 9+
:not() 全部 全部 全部 全部 9+
:valid/:invalid 10+ 4+ 5+ 12+ 10+
:checked 全部 全部 全部 全部 9+

六、注意事项与最佳实践

注意事项

  • 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 实现丰富的交互效果。核心原则是:交互必有反馈、结构善用伪类、表单即时验证

标签: CSS伪类 :hover :focus :nth-child 交互状态 结构伪类 表单验证

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: CSS溢出overflow详解:文本截断、滚动条控制与BFC应用 下一篇: CSS伪元素完全指南:::before、::after、排版伪元素与创意应用

poll相关推荐