一文吃透 CSS 伪类:从「鼠标悬停」到「斑马纹表格」的 30 个实战场景

0. 前言:为什么你总在写「多余」的 JS?

前端日常中,我们经常会写这样的代码:

js 复制代码
// 给每行表格隔行变色
trs.forEach((tr, i) => tr.style.background = i % 2 ? '#fff' : '#f7f7f7');

// 给按钮换色
btn.addEventListener('mouseenter', () => btn.style.background = '#eee');
btn.addEventListener('mouseleave', () => btn.style.background = '#fff');

伪类(Pseudo-class) 的存在,就是为了让浏览器帮你干这些「体力活」------一行 CSS 顶替十几行 JS,性能更好、可维护性更高,还能天然支持「未来新增的元素」。


1. 伪类到底是什么?

W3C 原话:

A pseudo-class is a keyword that specifies a special state of the selected element(s).

关键词:状态

伪类并不对应 HTML 中的真实 class,而是描述元素处于某种瞬时或结构上的状态 时该如何渲染。

语法:在选择器后加 : + 关键字,如 a:hoverli:nth-child(2n+1)


2. 伪类全家福(CSS Selectors Level 4 版)

类别 常用伪类 一句话记忆
用户行为 :hover :active :focus :focus-visible 悬停 / 按下 / 聚焦 / 键盘聚焦
表单反馈 :checked :disabled :valid :invalid :in-range :out-of-range ... 勾、禁、对、错、范围内、超范围
结构 / 序号 :first-child :last-child :nth-child() :nth-of-type() :only-child ... 第 n 个、倒数第 n 个、同类第 n 个
超链接历史 :link :visited 未访问 / 已访问
其他 :target :root :empty :not() 锚点、根节点、空节点、反选

3. 实战:不用伪类 vs 用伪类

3.1 隔行变色(斑马纹)

css 复制代码
/* ==== 1 行 CSS ==== */
.striped-table tbody tr:nth-child(2n) { background:#f7f7f7; }

不用伪类:

js 复制代码
// 还要考虑动态新增、排序、翻页......
document.querySelectorAll('tbody tr').forEach((tr,i)=>{
  tr.style.background = i%2 ? '#f7f7f7' : '';
});

3.2 自定义复选框

css 复制代码
/* 隐藏原生框,用兄弟元素画钩 */
input[type=checkbox] { display:none; }
input[type=checkbox] + label::before {
  content:'';
  display:inline-block;
  width:14px; height:14px;
  border:1px solid #999;
  margin-right:6px;
}
input[type=checkbox]:checked + label::before {
  background:#1890ff url(tick.svg) center/10px no-repeat;
}

不用伪类: 得监听 change 事件,手动增删 class。

3.3 聚焦输入框高亮

css 复制代码
.form-input:focus { border-color:#1890ff; box-shadow:0 0 0 2px rgba(24,144,255,.2); }

不用伪类:onfocus/onblur 来回改行内样式。

3.4 数字输入框范围提示

css 复制代码
input[type=number]:in-range  { border-color:#52c41a; }
input[type=number]:out-of-range { border-color:#ff4d4f; }

不用伪类:oninput 时读 value 再比大小。

3.5 空购物车提示

css 复制代码
.cart ul:empty::after { content:'购物车是空的,快去逛逛吧!'; color:#999; }

不用伪类: 得 JS 数 li 个数再插入/移除提示节点。

3.6 锚点定位高亮

css 复制代码
section:target { scroll-margin-top:80px; background:#fffbe6; }

点击目录跳转时,目标章节自动黄条高亮,无需任何脚本。

3.7 反选过滤

css 复制代码
button:not([disabled]) { cursor:pointer; }
/* 只给「可用」按钮加手型,禁用按钮忽略 */

4. 容易踩的坑

  1. 序号伪类是对所有兄弟节点 计数,而不是「同类名」。

    css 复制代码
    ul li:nth-of-type(2n) /* 同类标签第 n 个,不受其他元素干扰 */
  2. :hover 在触屏设备上可能「粘滞」,要加 @media(hover:hover) 做区分。

  3. :visited 为了隐私,能改的属性极少(color/border-color/background-color 且透明度必须为 1)。

  4. :focus:focus-visible 区别:后者只在「键盘tab」时出现,鼠标点击不显示,适合做「蓝框」。


5. 性能 & 可维护性

  • 浏览器内部对伪类做了高度优化,比手动 DOM 遍历快得多。
  • 样式与行为分离,产品要改「斑马色」设计师直接改 CSS,无需打扰 FE 重构。
  • 动态内容(ajax 翻页、拖拽排序)也不用重新执行染色脚本。

6. 彩蛋:纯 CSS Toggle 开关

css 复制代码
.toggle { display:none; }
.toggle + label { position:relative; width:40px; height:20px;
                  background:#ccc; border-radius:10px; cursor:pointer; }
.toggle + label::after { content:''; position:absolute; left:2px; top:2px;
                          width:16px; height:16px; background:#fff; border-radius:50%; transition:.3s; }
.toggle:checked + label { background:#1890ff; }
.toggle:checked + label::after { transform:translateX(20px); }
html 复制代码
<input class="toggle" id="t" type="checkbox"><label for="t"></label>

零 JS 即可得到 Material 风格滑动开关。


7. 速查海报(保存即可)

场景 一行代码
隔行变色 tr:nth-child(2n){background:#f7f7f7}
首项不同 li:first-child{font-weight:bold}
末项补灰线 li:last-child{border-bottom:none}
仅一项时隐藏「删除」按钮 ul li:only-child .del{display:none}
输入非法红框 input:invalid{border-color:#ff4d4f}
鼠标悬停放大 img:hover{transform:scale(1.1)}
键盘聚焦蓝环 button:focus-visible{outline:2px solid #1890ff}

8. 结语:把 JS 留給业务,把状态交給 CSS

伪类不是「小语法糖」,而是声明式编程 在前端的最好体现。

下次接到「奇偶行变色」「按钮按下换色」「表单验证红框」等需求,先想想:
能不能一行伪类解决?

能,你就省下:

  • 至少 10 行 JS
  • 一次 DOM 查询
  • 未来维护时踩坑的风险

把省下的时间用来写业务逻辑,或摸鱼,也是极好的。


9. 参考资料 & 延伸阅读

(完)

相关推荐
TE-茶叶蛋10 小时前
scss 转为原子css unocss
前端·css·scss
Sapphire~10 小时前
重学前端012 --- 响应式网页设计 CSS变量
前端·css
家里有只小肥猫10 小时前
css中的v-bind 动态变化
前端·css
超人不会飛10 小时前
LLM应用专属的Vue3 Markdown组件 🚀重磅开源!
前端·javascript·vue.js
NULL Not NULL10 小时前
ES6+新特性:现代JavaScript的强大功能
开发语言·前端·javascript
小高00710 小时前
🚄 前端人必收:5 分钟掌握 ES2025 超实用语法
前端·javascript·面试
程序员海军11 小时前
2025年上半年前端技术圈生态总结分享
前端·vue.js·react.js
记忆怪 bug11 小时前
2025前端面试题及答案(详细)
前端
群联云防护小杜11 小时前
服务器异常负载排查手册 · 隐蔽进程篇
运维·服务器·前端·数据库·笔记·sql·tcp/ip