:only-child要求元素是父元素唯一子节点(含文本/注释等),:only-of-type仅要求同类型元素在父元素中唯一;前者更严格易失效,后者更稳健适用动态内容。

:only-of-type 和 :only-child 看起来相似,但匹配逻辑完全不同——混用会导致样式意外失效或误命中,尤其在动态渲染、CMS 输出或第三方组件嵌入时极易翻车。
匹配条件:一个看“类型唯一”,一个看“子元素唯一”
:only-child 要求目标元素是父元素的**唯一子节点**(不管类型),即父元素下总共只有一个子元素,且就是它自己。哪怕多一个文本节点、注释或空格,都不匹配。
:only-of-type 只关心同类型元素是否唯一:父元素里可以有 <div>、<span>、文本、注释,只要其中**只有一个 p 元素**,那这个 p 就匹配 p:only-of-type。
-
<article><p>Hello</p></article>→p:only-child✅,p:only-of-type✅ -
<article><p>Hello</p><span>World</span></article>→p:only-child❌(有两个子节点),p:only-of-type✅(只有一个p) -
<article><p>A</p><p>B</p></article>→ 两个都 ❌(p不唯一,且父元素不止一个子节点)
常见错误:拼写、作用域、忽略隐式节点
拼错伪类名是最直接的失效原因:li:only-child-of-type 或 button:only-child 当作 :only-of-type 用,DevTools 里规则会直接灰掉。
立即学习“前端免费学习笔记(深入)”;
另一个高频坑是选择器前缀太宽泛:aside :only-of-type(注意空格)会匹配所有父级为 aside 的唯一类型子元素,比如 aside > p:only-of-type 和 aside > nav:only-of-type 都生效,容易样式污染。
还要警惕 HTML 中看不见的节点:换行、缩进空格、<!-- comment --> 都算子节点,会让 :only-child 失效,但对 :only-of-type 没影响。
该用哪个?看你的约束意图
想表达“这个元素底下没兄弟”——选 :only-child。典型场景:列表项内仅含一张图时去边框、卡片中只有一段文字时加大行高。
想表达“这个类型在父容器里只出现一次”——选 :only-of-type。典型场景:文章正文里单独一个 <figure> 居中、表单中唯一一个 <textarea> 自动拉高、侧边栏里仅有一个 <nav> 时加装饰线。
如果父结构不可控(如 CMS 导出、Markdown 渲染),优先用 :only-of-type;如果需要强排他性(比如动画触发条件),:only-child 更严格,但也更脆弱。
真要靠数量做判断?JS 才是最终兜底方案
CSS 伪类无法数“有几个 p”,也不能区分文本节点和元素节点。当业务逻辑要求“当且仅当存在两个 section 时应用样式”,或者需兼容 IE11(不支持这两个伪类),就得用 JS 查 el.children 或 el.querySelectorAll('p')。
另外,:only-of-type 在部分旧版 Safari(≤15.4)对自定义元素支持不稳定,若项目需兼容,建议加 class 降级处理。


















