:only-child几乎总不该直接用,因其严格要求父节点childNodes.length===1,换行、空格、注释等文本节点都会导致失效;实际需求多应使用更宽容的:only-of-type。

:only-child 几乎总是不该直接用——它太脆弱,DOM 里一个换行、空格或注释就让它失效。
为什么 :only-child 经常不生效
它不是看“页面上看起来只有一个子元素”,而是严格检查 parentNode.childNodes.length === 1。只要父节点里存在以下任一情况,:only-child 就跳过匹配:
- HTML 源码中任意换行或缩进(生成
#text节点) -
<!-- comment -->注释(Vue 的v-if编译后必留) - React 中的
<></>(不渲染,但计入childNodes) - 服务端模板(如 Twig、Nunjucks)默认保留空白
验证方法:选中目标父元素,在控制台运行 document.querySelector('p:only-child').parentNode.childNodes.length。如果不是 1,就别怪它没反应。
p:only-child 和 p:only-of-type 语义完全不同
混用等于白写,因为它们判断逻辑根本不同:
立即学习“前端免费学习笔记(深入)”;
-
p:only-child:父元素下总共只有一个子节点,且必须是<p>—— 容不得任何其他节点(哪怕<div>或换行) -
p:only-of-type:父元素下没有别的<p>,但可以有<div>、注释、换行等 —— 对真实 DOM 更宽容
90% 的“列表只剩一项时加圆角”“卡片只有一段文字时加大间距”这类需求,真正要的是 :only-of-type。
真要兜底,得从 DOM 层面确认数量
别低估文本节点的存在感——它不渲染,但会实实在在让 :only-child 失效。如果你必须用 :only-child,就得保证 HTML 是紧凑无换行的:<ul><li>xxx</li></ul>,连开头空格都不能有。
更现实的做法是:
- 用
:has(> li:only-of-type)配合现代浏览器(Chrome 105+ / Firefox 121+),但 Safari 尚未全支持 - 旧版兼容方案:服务端或构建阶段判断
parent.children.length === 1后加 class="single",再写.single > *
实际能跑通的写法,往往不是靠选择器猜,而是靠 DOM 数量可控——这点最容易被忽略。


















