直接写 .container:has(:nth-child(3)) 不生效,因为 :nth-child(3) 匹配的是第 3 个子元素本身,而非父容器;正确写法是 .container:has(*:nth-child(3)),表示存在至少 3 个子元素。

为什么直接写 .container:has(:nth-child(3)) 总是不生效
因为 :nth-child(3) 是在匹配“自身是第 3 个子元素”的目标,而你选的是父容器 .container——它不可能是自己的子元素。真正要检测“有没有第 3 个子元素”,必须用 *:nth-child(3),即任意元素作为第 3 个存在。
常见错误写法:.container:has(:nth-child(3))(无效)
正确写法:.container:has(*:nth-child(3))(表示至少 3 个)
如果 DOM 中混有文本节点(比如换行、空格),:nth-child() 会把它们也当子节点计数,导致判断偏移;确保子项全是块级元素(<div>、<code><section></section>),或提前用 display: contents 过滤掉干扰节点。
:has() 控制 Grid 列数时的三条硬规则
想让 .grid 在 1 个子项时单列、2–3 个时双列、4+ 个时三列,必须同时满足:
• 浏览器支持:Chrome 105+ / Firefox 121+ / Safari 16.4+(Safari 15.4–16.3 仅部分支持,不可靠)
• :has() 必须直接作用于 Grid 容器本身,不能写成 .grid > div:has(...) 或嵌套在 @media 里
• 规则顺序必须从“多”到“少”,否则会被覆盖:.grid:has(*:nth-child(4)) { grid-template-columns: repeat(3, 1fr); }.grid:has(*:nth-child(2)):not(:has(*:nth-child(4))) { grid-template-columns: repeat(2, 1fr); }.grid:not(:has(*:nth-child(2))) { grid-template-columns: 1fr; }
怎么精准匹配“恰好 n 个子元素”
用 :nth-child(n):nth-last-child(n) 组合,它等价于“第 n 个且倒数第 n 个”,总数必为 n。
• 恰好 1 个:.container:has(*:nth-child(1):nth-last-child(1))
• 恰好 2 个:.container:has(*:nth-child(2):nth-last-child(2))
• 恰好 3 个:.container:has(*:nth-child(3):nth-last-child(3))
注意:这个写法对 DOM 结构敏感。如果有非元素节点(如换行符生成的文本节点),:nth-last-child(3) 可能匹配不到真正的第三个子元素——此时 JS 清理或改用 childElementCount 更稳。
别指望 :has() 在 Flex 布局里自动调宽度
Flex 本身没有数量感知能力,:has() 只能间接影响 justify-content 或 flex-wrap,但不能替代 flex 计算逻辑。
例如想让 1 个子项撑满、2 个平分、3+ 个换行堆叠,不能只靠 :has() 改 flex 值,因为:
• flex: 1 是均分剩余空间,与数量无关
• justify-content: space-between 的间距由主轴长度和项目数共同决定,不是宽度问题
更可行的做法:
• 用 :has(*:nth-child(3)) 触发 flex-direction: column + flex-wrap: wrap
• 或者放弃纯 CSS,用 JavaScript 监听 MutationObserver,根据 parent.childElementCount 动态加类(如 count-1、count-2-plus),再由 CSS 定义各分支行为
真正难的不是语法,而是意识到:浏览器布局引擎不暴露“数量”这个变量,:has() 只是一次性布尔快照,不是运行时计算。











