:only-child 是选中父元素唯一子元素的最直接伪类,不区分类型,仅要求该元素是父元素的唯一子节点;若存在文本或注释节点则不匹配,IE9+ 全面支持。

选中首个且唯一的子元素,用 :only-child 最直接
如果目标元素既是第一个子元素,又是最后一个子元素(即父容器里只它一个),:only-child 就是专为此设计的伪类。它不关心元素类型,只看“是否唯一子元素”。比如 div > p:only-child 会匹配那些父 div 下仅有一个 p 的情况。
常见错误是以为 :first-child:last-child 更保险——其实它和 :only-child 在功能上等价,但多写一个伪类,解析开销略高,可读性反而下降;更关键的是,一旦后续加了 JS 动态插入节点,两者行为一致,没额外收益。
-
:only-child要求该元素是其父元素的**唯一子元素**(不管类型) - 若父元素下还有文本节点、注释节点或其它标签,
:only-child不会匹配(因为子元素数量 > 1) - 兼容性没问题:IE9+ 都支持,移动端也无顾虑
:first-child:last-child 能用,但没必要
这个组合确实能达成“唯一子元素”的效果,但它本质是两次筛选:先找第一个,再在其中挑最后一个。浏览器需分别计算两个伪类,再取交集。对现代引擎影响微乎其微,但代码冗余、语义绕弯。
典型误用场景是想“保险起见”,比如看到文档说 :only-child “可能不兼容老版本”,其实 IE8 及以下才不支持——而这些版本早已不在主流支持范围内。强行用 :first-child:last-child 还容易漏掉一个隐含前提:它只对同类型元素有效吗?不,它跟 :only-child 一样,不区分类型,只看 DOM 树位置。
立即学习“前端免费学习笔记(深入)”;
- 写
p:first-child:last-child和p:only-child行为完全相同 - 若父元素有空格或换行,生成的文本节点会让两者同时失效(不是“子元素”数量问题,而是“子节点”数量问题)
- 在 CSS-in-JS 或 Shadow DOM 中,节点结构更易受干扰,优先用语义明确的
:only-child
真正容易踩坑的是“看似唯一,实则不唯一”
很多开发者调试时发现 :only-child 没生效,翻来覆去查选择器,最后发现是 HTML 里写了换行或空格——这些都会变成 Text 类型的子节点,导致子节点总数 ≥ 2,哪怕视觉上只看到一个元素。
例如:
<div> <p>Hello</p> </div>这段代码中,
div 实际有 3 个子节点:换行符 + p + 换行符。所以 p:only-child 匹配失败。
- 用浏览器开发者工具的“Elements”面板,右键 → “Edit as HTML”,查看真实子节点结构
- 服务端渲染或模板引擎(如 Vue/JSX)中,注意是否开启了保留空白(
preserveWhitespace) - 如果必须容忍空白节点,改用 JavaScript 判断:
parent.children.length === 1(children只含元素节点)
需要“首个同类元素且唯一”?那得换思路
如果业务逻辑其实是:“我要选中父容器下第一个 span,而且这个 span 必须是唯一的 span”,那就不能只靠 :only-child——因为它不认元素类型,只要有一个 div 在旁边,span:only-child 就失效了。
这时没有纯 CSS 的单选择器解法。可行路径只有两个:
- 加 class 控制,比如让 JS 在唯一时添加
is-only-span类,再写span.is-only-span - 用
:first-of-type:last-of-type组合:它按元素类型计数,span:first-of-type:last-of-type表示“第一个span同时也是最后一个span”,允许中间穿插其它标签 -
:first-of-type:last-of-type在 IE9+ 支持,但 Safari 5.1 有 bug,若需兼容极老版本,仍建议 JS 辅助
:only-child 静静失效。










