用tr:nth-child(even)和tr:nth-child(odd)最简洁可靠,但必须限定作用域(如table tr或tbody tr),避免受thead、注释等干扰;IE8不支持需JS回退,且颜色对比度须符合可访问性标准。

用 tr:nth-child(even) 最简单实现隔行变色
直接给 <table> 里的 <tr> 加 CSS 伪类就能搞定,不用 JS、不改 HTML 结构。现代浏览器全支持,连 IE9+ 都能用。
常见错误是写成 tr:even(不存在这个伪类)或漏掉父容器作用域导致样式污染。正确写法:
table tr:nth-child(even) {
background-color: #f5f5f5;
}
table tr:nth-child(odd) {
background-color: #ffffff;
}
- 必须写
tr:nth-child(even),不是tr:nth-of-type(even)(后者会跳过<thead>里的<tr>) - 如果表格有
<thead>和<tbody>,建议把选择器限定在tbody tr,否则表头也会被算进:nth-child计数 - 颜色值推荐用十六进制或 rgba,避免用命名色(如
lightgray)——不同浏览器渲染不一致
兼容 IE8 只能用 class 手动标记
IE8 不支持 :nth-child,得靠 JS 或服务端加 class。前端最常用的是循环打标:
document.querySelectorAll('tbody tr').forEach((tr, i) => {
tr.classList.toggle('even', i % 2 === 0);
});
对应 CSS 就是:
立即学习“前端免费学习笔记(深入)”;
tr.even { background-color: #f5f5f5; }
- 千万别在 HTML 里手动写
<tr class="even">——维护成本高,增删行就错乱 - 如果用了 jQuery,
$('tbody tr:even').addClass('even')看似简洁,但 jQuery 的:even是从 0 开始计数,和 CSS 的:nth-child(even)行为一致;不过纯 JS 更轻量、无依赖 - 服务端渲染时(如 PHP/Python 模板),在循环输出
<tr>时用i % 2 == 0插入 class 更稳妥,避免页面闪动
遇到 <colgroup> 或合并单元格怎么办
:nth-child 只看 DOM 树位置,跟视觉行无关。如果有 <colgroup>、<caption> 或跨行 <tr>,计数不会跳过它们——但通常这些不在 <tbody> 里,影响不大。
- 真正要小心的是
<tbody>里混了<tr>和<template>或注释节点——:nth-child会把所有子节点计入,导致错位 - 合并单元格(
rowspan)不影响:nth-child,它只数<tr>标签数量,不管里面内容多高 - 如果表格动态插入行,记得重新运行 JS 打标逻辑,或者用事件委托 +
MutationObserver监听<tbody>变化
性能和可访问性容易被忽略的点
纯 CSS 方案几乎零性能开销,但颜色对比度不够会伤眼,尤其对弱视用户。
- 用
#f5f5f5和#ffffff对比度只有 1.1:1,远低于 WCAG 要求的 4.5:1;建议改用#f0f0f0/#ffffff或加一点灰度差(如#f8f8f8) - 不要仅靠颜色区分数据——色盲用户可能看不出差别,配合轻微边框或文字粗细变化更稳妥
- 如果表格支持键盘导航,确保焦点落在行内元素时,背景色变化仍清晰可辨(部分浏览器高亮会覆盖背景色)
隔行变色本身很简单,但真正在意细节的人,会在颜色值、作用域、可访问性上多花两分钟检查。



















