:has() 实现子元素数量布局需满足三条件:浏览器支持(Chrome 105+/Firefox 121+/Safari 16.4+)、写在父选择器上、规则按“从多到少”顺序叠加;:has(> *:nth-child(4)) 表示总数 ≥4,非恰好4个或>4。

:has() 能根据子元素数量改布局,但必须满足三个硬条件:浏览器支持(Chrome 105+ / Firefox 121+ / Safari 16.4+)、:has() 写在父选择器上、规则顺序按“从多到少”叠加,缺一不可。
为什么 :has(> *:nth-child(4)) 不起作用?
它只表示“存在第 4 个子元素”,即总数 ≥ 4;不是“恰好 4 个”,也不是“大于 4”。常见失效原因包括:
-
:has()被写在子元素选择器上(如div > span:has(+ span)),浏览器直接忽略整条规则 - 父容器内混入文本节点(换行、空格)或注释——
:has()只匹配元素节点,计数会跳过它们 - 规则写在
@media或@supports块里,部分旧版 Safari 不支持嵌套中的:has() - 误用
:has(:nth-child(4))(要求自身是第 4 个子),正确写法是:has(> *:nth-child(4))
怎么写才能实现「1–3 个 → 1 列,4–6 个 → 2 列,7+ 个 → 3 列」?
CSS 没有 > 或 < 运算符,只能靠“是否存在第 N 个子”来逼近范围。关键在书写顺序和否定组合:
-
.grid:has(> *:nth-child(7))→ 至少 7 个(≥7) -
.grid:has(> *:nth-child(4)):not(:has(> *:nth-child(7)))→ ≥4 且 <7,即 4–6 个 -
.grid:not(:has(> *:nth-child(4)))→ <4,即 1–3 个
顺序不能颠倒,否则 :not(:has(...)) 会覆盖前面更具体的规则。
立即学习“前端免费学习笔记(深入)”;
如何精准匹配「恰好 n 个子元素」?
用 :has(> *:nth-child(n):nth-last-child(n)),例如:
-
.container:has(> *:nth-child(1):nth-last-child(1))→ 恰好 1 个 -
.container:has(> *:nth-child(3):nth-last-child(3))→ 恰好 3 个
这个写法对 DOM 结构敏感:所有子项必须是同级块级元素(如 <div>),且不能有文本节点干扰。若有空格/换行生成的文本节点,:nth-last-child() 计数会错位,得用 display: contents 或 JS 清理。
真正难的不是写出语法,而是意识到 :has() 是一次性结构快照判断——它不感知动态变化,也不等价于 children.length。一旦项目要兼容 Safari 15.x 或旧版 Firefox,就得准备 JS 注入 class 的兜底方案。


















