:nth-child(-n+3)按子节点位置选前三个,要求元素同级且类型匹配;若中间有其他节点(如div、注释),则可能跳过目标元素。

为什么 :nth-child(-n+3) 选不到你想要的前三个元素?
它确实能选前三个,但前提是这些元素必须是同级、且类型匹配。比如你在 <ul></ul> 里写 li:nth-child(-n+3),它只选「位置在第1–3且本身是 li」的元素——如果前三个子节点里夹着一个 <div> 或注释节点,那这个 <code>li 就可能被跳过。常见错误是以为它按「第几个 li」计数,实际它是按「第几个子节点」计数。
验证方法:打开开发者工具,用 document.querySelectorAll('li:nth-child(-n+3)') 看返回结果,再对比 document.querySelectorAll('li') 的索引顺序。
:nth-of-type(3) 和 :nth-child(-n+3) 到底该用哪个?
看你要的是「前三个同类型兄弟」还是「前三个位置上的子元素」:
-
:nth-child(-n+3):严格按 DOM 树中的子节点序号筛选,不管类型。适合结构干净、无干扰节点的容器(如纯li列表) -
:nth-of-type(-n+3):只统计同标签名的兄弟节点,忽略其他类型。更鲁棒,比如div > p:nth-of-type(-n+3)能稳稳选中前三个p,哪怕中间插了<span></span>或<hr> - 注意:
:nth-of-type()不支持伪元素(如::before),也不适用于自定义组件(如 Vue 的<my-comp></my-comp>在未提升为真实标签时无效)
配合 :not() 排除特定元素后再取前三个
真实项目里常要「前三个非禁用项」或「前三个非广告位」。这时不能只靠 -n+3,得组合过滤:
立即学习“前端免费学习笔记(深入)”;
例如排除带 data-ad="true" 的卡片后取前三个:
article:not([data-ad="true"]):nth-of-type(-n+3)
但注意:这个选择器是「先各自匹配 :not(),再在所有匹配结果里按类型序号取前三个」,不是「先筛出非广告项,再取其中前三个」——CSS 没有「管道式」执行顺序。真正可靠的写法是用 JS 动态加 class,或改用 display: none 隐藏干扰项后再用 :nth-child(-n+3)。
另一个坑::not(.disabled):nth-child(-n+3) 会失效,因为 :nth-child() 计算时仍把 .disabled 元素算进序号里。
性能与兼容性提醒:别在复杂列表里滥用
:nth-child() 和 :nth-of-type() 在现代浏览器中性能尚可,但在以下场景容易卡顿或行为异常:
- 父容器含上千子节点(尤其是动态渲染的长列表),每次重排都触发全量计算
- IE 8 及更早版本完全不支持,IE 9–11 支持
:nth-child()但不支持:nth-of-type()的负系数(-n+3在 IE 中会被忽略) - 某些 CSS-in-JS 库(如 styled-components v4)对复杂伪类解析不稳定,建议降级为 class 控制
如果目标只是视觉上「只显示前三个」,flex + overflow: hidden 或 JS 截断 innerHTML 往往比纯 CSS 更可控。


















