:nth-child(odd)和:nth-child(even)按父元素所有子元素的物理位置序号匹配奇偶项,非仅同类标签;混入其他节点会导致错位,应限定作用域或改用:nth-of-type()提升容错性。

用 :nth-child(odd) 和 :nth-child(even) 实现奇偶变色
这是最直接、兼容性最好的方案,现代浏览器(包括 IE9+)都支持。关键不是“奇偶”字面意思,而是元素在父容器中的位置序号:第 1、3、5… 项匹配 :nth-child(odd),第 2、4、6… 项匹配 :nth-child(even)。
注意::nth-child() 看的是 DOM 顺序,不是列表项个数或内容是否为 <li>。如果父元素里混有其他标签(比如 <div> 或注释节点),序号会受影响。
<p>实操建议:</p>
<ul>
<li>确保目标列表项是连续的子元素,中间不要插其他类型标签</li>
<li>写法示例:<pre class="brush:php;toolbar:false;">ul li:nth-child(odd) { background: #f0f0f0; }<br>ul li:nth-child(even) { background: #e0e0e0; }</pre>
</li>
<li>如果列表嵌套或结构复杂,优先用 <code>:nth-of-type() 替代(见下一条)
当列表中混有非 <li> 元素时,改用 :nth-of-type()
:nth-of-type() 只统计同类型标签(如所有 <li>),忽略其他兄弟节点。适合真实项目中常见的“标题 + 列表项 + 分隔线”结构。
常见错误现象:加了 :nth-child(even) 却发现颜色错位,往往是因为前一个 <h3></h3> 或 <div class="divider"> 占据了序号 1,导致第一个 <code><li> 实际是第 2 个子元素,被当成 “even” 处理。
实操建议:
- 把选择器从
li:nth-child(odd)改成li:nth-of-type(odd) - 它只对
<li>标签计数,不管前面有没有<h2></h2>或空<div> <li>IE9+ 同样支持,但不支持更复杂的公式如 <code>:nth-of-type(3n+1)(IE 下仅接受odd/even) -
:first-child只能固定影响第一个<li>,哪怕你后续插入新项,它还是那个“第一个” - 无法表达“所有奇数位”,必须配合 JS 手动 toggle class,成本远高于纯 CSS 方案
- 若列表首项被
display: none或visibility: hidden,:first-child仍生效,但视觉上不可见,容易引发调试困惑 - 如果用
innerHTML += '<li>...</li>',整个父元素会重建,所有子元素重排,序号重置——此时没问题 - 如果用
insertBefore()插到中间,序号会重新分配,样式实时更新 - 唯一例外:IE8 及更早版本完全不支持这些伪类,需降级为 JS 控制 class
避免用 :first-child 或 :last-child 做奇偶逻辑
这两个伪类只匹配第一个或最后一个子元素,和奇偶无关。有人误以为 li:first-child 能替代 :nth-child(odd) 的“首个”,但一旦列表动态增删,逻辑就断了——它不会随数量变化自动调整“奇数位”样式。
使用场景限制明显:
动态列表(JS 插入)下伪类是否自动生效?
是的,只要新 <li> 正确 append 到父容器末尾,:nth-child() 和 :nth-of-type() 会自动重算并应用样式,无需手动触发重绘。
但要注意边界情况:
真正容易被忽略的是:服务端渲染时若 HTML 已含部分 <li>,而前端 JS 又追加一批,两者序号连贯计算——不是“服务端的 odd + JS 的 odd”,而是一整套连续编号。这点在分页或懒加载列表里特别关键。











