:nth-child(-n+3)只能选中位置在第1–3且类型匹配的元素,因它按父元素所有子节点(含注释、文本等)统一编号;结构不干净时易失效,应优先用:nth-of-type(-n+3)或js筛选。

它能选前三个,但只在 DOM 结构干净、目标元素恰好占据第 1–3 个子节点位置时才可靠;否则大概率失效。
为什么 :nth-child(-n+3) 常常“看起来没生效”
这个选择器不是按“第几个目标元素”计数,而是按父元素下所有子节点(包括 <div>、<code><p></p>、注释、换行空白文本节点)统一编号。只要前三个位置里混入非目标标签或不可见节点,匹配就中断。
- 例如父容器是
<ul> <li>A</li> <li>B</li> <div class="sep"></div> <li>C</li> </ul>,那么li:nth-child(-n+3)只能命中前两个<li>,第三个<li>是第 4 个子节点,不匹配 - HTML 中的换行和缩进会生成
Text节点,在 IE 或严格解析模式下也被计入序号 - 用
innerHTML动态替换内容后,若未触发重排,浏览器仍按旧 DOM 树计算位置
:nth-child(-n+3) 和 :nth-of-type(-n+3) 必须分清
前者看位置,后者看类型。你要的是“前三个 <li>”,而不是“位置在前三位的任意元素”,那必须用后者。
-
li:nth-child(-n+3):只匹配「是<li>且在父元素中排第 1、2 或 3 位」的元素 -
li:nth-of-type(-n+3):对所有<li>单独编号,选其中第 1、2、3 个,不管中间夹着什么 - 注意:
:nth-of-type()不支持自定义组件标签(如<my-card></my-card>),也不匹配伪元素(::before)
怎么安全地选“前三个带 .item 的元素”
如果结构不可控(比如 SSR 渲染插入了注释、服务端模板有空格、JS 动态插入了广告位),纯 CSS 很难兜底。
- 最稳方案是 JS 预处理:
document.querySelectorAll('.item').slice(0, 3).forEach(el => el.classList.add('first-three')),再写.item.first-three { ... } - 若坚持用 CSS,先确保干扰项被移除或隐藏:给广告、分隔线等加
display: none,再用.item:nth-child(-n+3) - 组合
:not()有陷阱:.item:not([data-ad]):nth-child(-n+3)仍按原始序号计算,.item 元素被跳过时,后续编号不会自动前移
范围截取别硬套公式,先确认结构是否可控
要选第 3 到第 6 个,写 :nth-child(n+3):nth-child(-n+6) 没问题;但一旦父容器里有不可预测的节点插入(比如 CMS 自动加的 <hr> 或埋点 <span></span>),这个范围就会偏移。
- Flex/Grid 布局中,
order属性不影响:nth-child(),它永远只认 HTML 源顺序 - IE9–11 支持
:nth-child(),但不支持:nth-of-type(-n+3)中的负系数(-n+3在 IE 中会被忽略) - 真正难的不是写出
-n+3,而是判断当前场景下 DOM 是否稳定——不稳定就别赌 CSS 选择器











