:first-child未选中第一个p是因为它只匹配父元素的第一个子节点且类型必须为p;若父元素首个子节点是h2或注释等,p:first-child即失效,此时应改用p:first-of-type。

为什么 :first-child 没选中第一个 <p></p>?
因为 :first-child 匹配的是其父元素的**第一个子元素**,且必须是该类型。如果父容器里第一个子元素是 <h2></h2>,后面才是 <p></p>,那所有 <p></p> 都不会被 p:first-child 选中——它们都不是父元素的第一个子节点。
常见错误现象:p:first-child 在结构如 <div>
<h2>标题</h2>
<p>正文</p>
</div> 中完全不生效。
- 确认目标元素是否真是父元素的首个子节点(用浏览器开发者工具看 DOM 树)
- 若只需选“第一个
p”,改用:nth-of-type(1)更可靠 -
:first-child对元素类型敏感,div:first-child不会匹配<span><div>…</div></span>中的div,因为div不是span的子元素
:last-child 在动态插入内容时为何失效?
它只看当前 DOM 结构中的**最后一个子节点**,不关心内容或 class。如果 JS 向父容器末尾追加一个 <div class="spacer"></div>,原先的最后一个 <p></p> 就立刻失去 :last-child 状态。
使用场景:给列表最后一项去下边框、给卡片组最右一项去右边距——但前提是结构稳定。
- 避免依赖
:last-child控制关键布局,尤其在有 JS 动态增删节点的页面 - 替代方案:给父容器加
display: flex,用margin-right: auto或gap控制间距 - 若必须用,可配合
:not(:last-child)统一设置中间项样式,例如li:not(:last-child) { border-bottom: 1px solid #eee; }
:first-child 和 :first-of-type 到底差在哪?
区别在于匹配逻辑::first-child 是“位置优先”,:first-of-type 是“类型优先”。前者要求既是第一个子节点,又是目标标签;后者只要求是该标签在父元素中出现的第一个实例。
示例结构:<ul>
<li>A</li>
<p>note</p>
<li>B</li>
</ul>
-
li:first-child→ 匹配第一个<li>A</li>(它是第一个子节点,且是li) -
li:first-of-type→ 也匹配<li>A</li>(它是第一个出现的li) - 但如果结构变成
<ul> <p>note</p> <li>A</li> <li>B</li> </ul>:li:first-child→ 不匹配任何li(第一个子节点是p)li:first-of-type→ 匹配<li>A</li>
兼容性和性能要注意什么?
:first-child 和 :last-child 自 IE9 起就支持,现代项目基本无兼容问题。但性能上,它们属于“关系型伪类”,浏览器需遍历父元素全部子节点才能判定,嵌套过深或子节点极多时(比如渲染上千行表格),可能轻微拖慢样式计算。
- 不要在
body或html这种含大量子节点的顶层元素上滥用这些选择器 - 避免链式写法如
section > div > p:first-child,层级越深,重排重绘开销越高 - 若只是为首尾项加简单修饰(如圆角、边框),用 class 显式标记(如
class="first")反而更轻量、更可控
真正容易被忽略的是:这两个选择器对空白文本节点也敏感。换行符、缩进空格在 DOM 中可能生成 Text 节点,导致你以为的“第一个元素”其实前面有个空格节点,:first-child 就失效了。检查时打开开发者工具的“显示文本节点”选项(Chrome DevTools 设置里可开启),比单纯看 HTML 源码更准。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











