:nth-child(n)按父元素所有子节点总序号计数,:nth-of-type(n)仅按同标签兄弟节点计数;DOM中注释、空格、div等干扰节点会导致:nth-child失效,而:nth-of-type不受影响。

因为它们数的根本不是同一批东西。 :nth-child(n) 数父元素下所有子节点的总序号,:nth-of-type(n) 只数同标签名的兄弟节点——中间夹个 <div>、换行、注释,结果立刻分叉。
看 DOM 真实结构才能理解为什么失效
浏览器不会按你“以为”的顺序数。比如这段 HTML:
<article> <h2>标题</h2> <p>第一段</p> <div class="ad"></div> <p>第二段</p> </article>
此时:
-
p:nth-child(2)匹配第一个<p>(它是第 2 个子元素) -
p:nth-child(4)才匹配第二个<p>(前面多了<h2>和<div>) -
p:nth-of-type(2)直接命中第二个<p>,完全无视中间那堆干扰
常见错误现象:开发时有效,上线后样式消失
根本原因不是 CSS 写错了,而是构建工具压缩 HTML 或 CMS 插入了不可见节点。比如:
立即学习“前端免费学习笔记(深入)”;
- 服务端模板里加了
<!-- header -->→ 多一个注释节点,:nth-child全部偏移 - Markdown 渲染器在段落间自动插入空行 → 生成空白 textNode,悄悄改变子节点序号
- 富文本编辑器导出 HTML 时混入
<span class="anchor">→:nth-child把它当普通子元素计数
什么时候必须用 :nth-of-type?
当你真正想表达的是“第 N 个 <p>”“第 3 个 <button>”,而不是“从上往下数第 N 个位置、且那里碰巧是 <p>”时,就该切到 :nth-of-type。
- 文章正文渲染(CMS/Markdown 输出结构不可控)
- 表单字段组:
label + input + span.error混排,但你想给第 2 个<input>加边框 - 新闻卡片:
h2 + time + p + button,要高亮第 3 个<button> -
div.foo:nth-of-type(2)中的.foo不影响计数,只作附加筛选
容易被忽略的底层细节
伪类作用域永远只限于**直接父元素的子节点**。写 section p:nth-of-type(2),它不会遍历整个 section 树,只会检查 section 的直接子元素中哪些是 <p>,再从中取第 2 个。
另外,:nth-child(0) 无效(n 必须 ≥ 1),odd/even 必须小写,IE8 完全不支持 :nth-of-type——这些不是语法问题,而是 DOM 解析逻辑和兼容性边界,每次写之前,先右键父元素 →「Edit as HTML」看一眼真实子节点构成,比查文档更快定位问题。


















