最简洁可靠的纯CSS方案是tbody tr:nth-child(even)和tbody tr:nth-child(odd),必须显式包裹tbody以避免thead干扰计数;nth-of-type在含thead的表格中易错位,IE8需JS降级,高对比度模式下背景色可能被系统覆盖。

用 tbody 和 tr:nth-child(even/odd) 实现语义化交替色
纯 CSS 方案最简洁,且不破坏表格语义结构。关键前提是确保 tbody 存在(浏览器会自动补全,但显式写出更可控),避免把样式逻辑塞进 class 或 JS 中。
常见错误是直接对 table tr 用 :nth-child,结果表头(thead tr)也被计入序号,导致第一行数据变色异常。正确写法必须限定作用域:
table tbody tr:nth-child(even) {
background-color: #f5f5f5;
}
table tbody tr:nth-child(odd) {
background-color: #ffffff;
}
- 务必显式包裹
tbody,尤其当表格含thead或tfoot时 -
:nth-child(even)从第 2 行开始匹配,不是“偶数索引”,而是“位置为偶数的子元素” - 若表格动态增删行,该规则仍自动生效,无需 JS 干预
为什么不用 tr:nth-of-type()?
:nth-of-type() 看的是标签类型,不是 DOM 位置。在含 thead、tfoot 的表格中,tbody tr 和 thead tr 都是 tr,但 :nth-of-type(2) 会选中 thead 里的第二行(如果存在),而非 tbody 里第二行 —— 容易错位。
示例对比:
立即学习“前端免费学习笔记(深入)”;
<table>
<thead><tr><th>Name</th></tr></thead>
<tbody>
<tr><td>Alice</td></tr>
<tr><td>Bob</td></tr>
</tbody>
</table>
此时 tr:nth-child(2) 匹配 tbody 第一行(Alice),而 tr:nth-of-type(2) 匹配 thead 里的 tr(如果它有两行)或跳过 thead 后计数混乱 —— 不可靠。
需要兼容 IE8 怎么办?
IE8 不支持 :nth-child(),但也不支持现代语义化表格结构的完整解析。真要兼容,只能退回到 JS 注入 class 的方案,但必须避开污染语义:
- 遍历
document.querySelectorAll('tbody tr'),而非table tr - 只给
tr添加row-even/row-odd这类描述性 class,不带颜色含义 - CSS 用
tr.row-even控制样式,保持样式与结构分离 - 避免用
tr:nth-child(1)这种脆弱选择器做 fallback
注意:若表格含 colspan 或 rowspan,JS 方案不会出错,但 CSS :nth-child 本身也不受影响 —— 它只看 DOM 树中的兄弟顺序,和单元格合并无关。
可访问性与高对比度模式下的坑
交替背景色在高对比度模式(如 Windows 系统级开启)下会被强制覆盖为系统主题色,可能让所有行变成同色。这不是 bug,而是 WCAG 要求:用户代理有权重置颜色以保障可读性。
因此:
- 不要依赖背景色传递关键信息(比如“红色=错误”),必须辅以图标、文字标识或
aria-label - 避免用太浅的灰(如
#fafafa)作交替色,暗色模式下可能和背景混在一起 - 检查焦点状态:当某行
tr获得焦点(例如整行可点击),:focus-within样式不能被交替色淹没
真正麻烦的从来不是怎么画出两种颜色,而是让它们在各种上下文里不抢戏、不误导、不消失。



















