:first-child不生效是因为它只匹配父元素下第一个子节点且类型必须完全一致;若首个子节点是注释、空文本或其它元素,即使目标元素是首个该类型也会失效。

为什么 :first-child 有时不生效?
因为 :first-child 匹配的是父元素下「第一个子元素」,且必须是该类型——不是「第一个 h2」,而是「第一个子节点且恰好是 h2」。如果首个标题前有注释、空文本节点、<div> 或 <p>,它就直接失效。
常见错误现象:h2:first-child { color: red; } 在 CMS 渲染后完全没反应,实际 HTML 开头是 <!-- intro --><h2>标题</h2>,注释节点占了“第一个”位置。
- 检查 DOM 结构:用浏览器开发者工具右键「Reveal in Elements Panel」,确认目标元素是否真为第一个子节点
- 若不确定前置内容,改用
:nth-of-type(1)更可靠(它只看同类型兄弟节点) -
:first-of-type和:first-child不等价:前者找同类中排第一的,后者认死理只看顺序
如何精准选中首个 <h2> 并加装饰边框?
场景很典型:文章正文开头的主标题需要视觉强化,但后续 <h2> 要保持默认样式。用 :first-of-type 是最稳的选择,尤其当 <h2> 前可能有 <p>、<figure> 等其他元素时。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 写成
h2:first-of-type { border-top: 3px solid #2a58a2; padding-top: 0.5em; } - 避免用
h2:nth-child(1)——它要求 h2 必须在第一位,太脆弱 - 注意继承干扰:如果父容器设了
font-weight: bold,这个加粗会透给所有 h2,需显式重置h2:first-of-type { font-weight: 700; }
:first-child 在 Flex/Grid 容器里还管用吗?
管用,但逻辑不变:它仍按 DOM 顺序判断,和布局方式无关。Flex 或 Grid 只改变渲染位置,不改变节点树结构。
容易踩的坑:
- 不要以为把某个
<h2>用order: -1提到最前,它就能触发:first-child——DOM 顺序没变,伪类不买账 - Grid 中用
grid-template-areas重排区域,同样不影响:first-child的匹配结果 - 真正想按视觉顺序控制样式,得靠 JS 计算或预设 class(比如服务端渲染时加
class="first-section-title")
兼容性与性能要注意什么?
:first-child 和 :first-of-type 都是 CSS2.1 就支持的伪类,IE9+ 全支持,移动端无压力。性能上也没额外开销——浏览器解析时本就要遍历子节点顺序,伪类只是复用已有信息。
但有个隐蔽问题常被忽略:
- 如果父容器是动态插入内容(比如 Vue/React 的条件渲染),首次渲染时没有 h2,后来才加进去,那么
h2:first-of-type会立即生效;但若用 JS 手动插入多个 h2 再删掉第一个,伪类不会自动重新判定“首个”,得靠强制重排(如offsetHeight)或重设 class 触发 - 服务端渲染(SSR)场景下,若首屏 HTML 里没有 h2,而 JS 加载后才注入,CSS 选择器无法“等待”元素出现——这时必须配合 JS 控制 class
真正难的不是写对伪类,而是搞清你到底想响应「DOM 顺序」还是「视觉意图」。前者用 :first-of-type 基本够用,后者往往得让 CSS 退一步,把决定权交给结构标记或 JS。


















