:nth-child(-n+3) 匹配父元素下第1至3个子节点,不论类型;当存在非目标标签(如<p>)时,会导致实际选中的不是前三个<li>,应改用:nth-of-type(-n+3)或逐个声明。

:nth-child(-n+3) 确实能选中前三个子元素,但它依赖的是「位置」而非「是否是目标类型」——这点容易误用,尤其当列表里混有其他标签时。
为什么 :nth-child(-n+3) 有时不生效?
它匹配的是父元素下第 1、2、3 个子节点,不管这些节点是不是你要的元素。比如:<ul><li>A</li><p>干扰项</p><li>B</li><li>C</li></ul> 中,:nth-child(-n+3) 实际匹配的是第一个 <li>、那个 <p> 和第二个 <li>,第三个 <li> 反而被跳过(它是第 4 个子节点)。
更可靠的写法:用 :nth-of-type(3) 或 :nth-child(3) 组合
如果目标是纯 <li> 列表且中间没插入其他标签,:nth-child(-n+3) 完全可用;但只要结构稍复杂,就该换思路:
- 用
:nth-of-type(-n+3)—— 它只统计同类型(如<li>)的兄弟节点,不受中间杂项影响 - 若只需样式控制且兼容性要求不高,
li:nth-of-type(1), li:nth-of-type(2), li:nth-of-type(3)更直白、易调试 - 注意:IE8 不支持
:nth-of-type,若需兼容,得退回到 JS 遍历或加 class
快速验证是否真选中了前三个 <li>
在 DevTools 控制台执行这行就能确认:
立即学习“前端免费学习笔记(深入)”;
$$('ul li').slice(0, 3).map(el => el.outerHTML)
再对比 $$('ul li:nth-child(-n+3)') 的结果——两者不一致?说明 DOM 结构里有非 <li> 元素干扰了索引计算。
真正麻烦的不是公式记不住,而是默认以为「前三个 <li>」和「前三个子元素」是一回事;实际项目里,DOM 往往带注释、空格文本节点、或服务端注入的提示 <div>,这些都会悄悄改变 :nth-child 的计数起点。


















