nth-child按子节点总序号匹配,不区分类型;nth-of-type仅在同类型兄弟中计数。二者均作用于直接子元素,IE9+支持,性能无差异。

nth-child 选的是位置,不关心元素类型
只要父元素下第 n 个子节点恰好满足条件(比如 2n),就命中,哪怕它是 <p>、<div> 或注释节点。浏览器按 DOM 树顺序从 1 开始数子节点,完全忽略标签名。
常见错误现象:div:nth-child(2) 没生效,其实是因为第二个子节点是 <span>,不是 <div> —— 它根本不会去“找第二个 div”,只看“第二个孩子是不是 div”。
- 适用于需要按视觉/结构顺序统一控制的场景,比如表格奇偶行、网格中固定列偏移
- 对 DOM 变动敏感:在开头插入一个
<header>,所有:nth-child(n)的匹配结果都会偏移 - 支持复杂公式如
:nth-child(3n+1),但始终基于总子节点序号计算
nth-of-type 只看同类型兄弟节点的顺序
:nth-of-type(n) 会先筛选出和当前选择器标签名一致的兄弟节点(比如所有 <p>),再在这些同类节点里按出现顺序编号,取第 n 个。
使用场景典型:文章正文里想给“第 3 个段落”加样式,不管前面有没有 <img>、<h2> 或空 <div> —— 只要它是第 3 个 <p> 就行。
立即学习“前端免费学习笔记(深入)”;
- 更符合语义直觉,尤其在 CMS 输出不可控 HTML 时更鲁棒
- 不匹配自闭合标签(如
<br>)的“类型”,因为它们没有结束标签,不参与同类型计数逻辑 - 注意:伪元素(如
::before)不参与任何:nth-计算,它们不在 DOM 子节点中
混用时容易踩的坑:div:nth-child(2) ≠ div:nth-of-type(2)
假设有如下 HTML:
<article> <h2>标题</h2> <p>第一段</p> <div>容器</div> <p>第二段</p> </article>
那么:
-
p:nth-child(2)→ 匹配“第一段”,因为它是第 2 个子节点 -
p:nth-of-type(2)→ 匹配“第二段”,因为它是第 2 个<p> -
div:nth-child(3)→ 匹配那个<div>,因为它是第 3 个子节点 -
div:nth-of-type(1)→ 同样匹配它,因为它是唯一一个<div>
如果删掉 <h2>,p:nth-child(2) 就会从匹配“第一段”变成匹配“第二段”,而 p:nth-of-type(2) 始终不变。
性能与兼容性其实没差别
两者在现代浏览器中解析开销几乎一致,都不是性能瓶颈。真正影响渲染效率的是选择器整体复杂度(比如嵌套过深、通配符滥用),而不是 nth-child 和 nth-of-type 的差异。
兼容性方面,IE9+ 都支持,但 IE8 及更早版本完全不支持这两个伪类 —— 如果还要兼容,得用 class 手动标记或 JS 补充。
最常被忽略的一点:它们都只作用于**直接子元素**。写成 section p:nth-of-type(1) 是合法的,但这里的 :nth-of-type(1) 是针对每个 <p> 在其**各自父容器内**计数,不是在整个 <section> 下所有 <p> 统一排序。


















