:nth-child(-n+3)匹配父元素中位置为第1、2、3的子节点(无论类型),依赖所有子节点(含文本、注释)的物理序号;混入非目标标签或空白节点时易失效,此时应改用:nth-of-type(-n+3)或显式声明。

什么是 :nth-child(-n+3) 的实际含义
这个伪类不是“选前三个”,而是“选所有满足 n ≤ 3 的第 n 个子元素”——它依赖于元素在父容器中的**物理位置**,且只匹配那些**恰好是第 1、2、3 个子节点**的元素,不管它们是什么类型或有没有 class。
常见误解是以为它像 :nth-of-type() 那样按元素类型筛选,但它不是。比如父元素里第 1 个是 <div>、第 2 个是 <code><p></p>、第 3 个是 <span></span>,这三者都会被选中;但如果第 2 个是注释节点或文本节点(非元素节点),那第 2 个 <div> 实际可能是第 3 个子元素,就可能被跳过。
<h3>什么时候用 <code>:nth-child(-n+3) 真正有效
它最适合结构干净、子元素全是目标类型且顺序可控的场景,比如手写列表、卡片容器、表格行(<tr>)等。
<ul>
<li>父元素下只有你要操作的元素,没有空格文本节点(HTML 中换行缩进会生成 text node)</li>
<li>不需要兼容 IE8 及更早版本(<code>:nth-child 在 IE9+ 支持)
:nth-child(-n+3) 和 :nth-of-type(-n+3) 的关键区别
如果父元素混有多种标签,比如:
立即学习“前端免费学习笔记(深入)”;
<ul> <li>A</li> <p>not a list item</p> <li>B</li> <li>C</li> <div>also not</div> </ul>
那么:
-
li:nth-child(-n+3)→ 只匹配第一个<li>(它是第 1 个子元素),<p></p>是第 2 个子元素所以不匹配,第二个<li>是第 3 个子元素 → 匹配,第三个<li>是第 4 个子元素 → 不匹配。结果:只选中 A 和 B -
li:nth-of-type(-n+3)→ 忽略<p></p>和<div>,只数 <code><li>:A 是第 1 个<li>,B 是第 2 个,C 是第 3 个 → 全部匹配容易被忽略的 DOM 细节导致失效
最常见的“写了但没生效”,往往不是语法错,而是 DOM 结构干扰了子元素序号:
- HTML 换行缩进产生空白 text node,让第一个目标元素变成第 2 个子节点
- 使用了 Vue/React 等框架,模板编译后插入了注释节点(如
<!--v-if-->) - 父元素内有
<script></script>或<style></style>标签(虽不渲染,但算子节点) - 用了
display: contents的子元素不参与盒模型,但仍计入:nth-child计数
调试时可用浏览器开发者工具的 Elements 面板右键「Break on > subtree modifications」,再检查
childElementCount和childNodes.length是否一致。真正想“稳稳选前三个目标元素”,多数情况下应优先考虑加 class(如
.featured)或改用 JS 控制,而不是押注于 DOM 序号的稳定性。


















