:has() 不能计数,只判断存在性;正确写法需带空格和通配符如 .container:has(*:nth-child(3));其调整间距依赖父容器属性且受 DOM 节点类型和浏览器版本限制。
:has() 检测子元素数量时 spacing 没变化根本原因不是样式写错了,而是你可能把 :has() 当成“计数器”用了——它不返回数字,只回答“第 N 个子元素是否存在”。比如 .container:has(:nth-child(3)) 实际匹配的是“.container 自身是第 3 个子元素”,这永远为假;正确写法必须带空格和通配符:.container:has(*:nth-child(3)),表示“容器下存在第 3 个子元素”。漏掉 * 或空格,整个规则静默失效。
:has() 调整间距的可靠写法直接改 gap、padding 或 margin 是最常见需求,但要注意:这些属性作用于父容器自身,所以 :has() 必须作为父选择器的一部分出现,且不能嵌套在 @media 或 @supports 里(旧版 Safari 会忽略)。
.container 默认设基础间距:gap: 0.5rem;
.container:has(*:nth-child(2)) { gap: 1rem; }
.container:has(*:nth-child(4)) { gap: 1.5rem; }
.container:has(*:nth-child(3)):not(:has(*:nth-child(4))) { gap: 1.25rem; }
注意顺序:从大数量到小数量排列规则,否则 :has(*:nth-child(2)) 会覆盖后续更精确的判断。
:has() 只匹配元素节点,文本、注释、空格都会导致计数偏移。比如:
立即学习“前端免费学习笔记(深入)”;
<div class="container"> <div>A</div> <div>B</div> <!-- comment --> <div>C</div></div>
这段 HTML 实际有 4 个子节点,但只有 3 个 <div> 元素。.container:has(*:nth-child(3)) 匹配的是第三个子节点(即注释),不是第三个 <div>——结果就是规则不触发。解决方法:确保子元素是连续的同级标签,或改用 :has(.item:nth-of-type(3))(前提是所有目标子元素都是同类型标签)。
@supports not selector(:has(*)) 是必须加的包裹层,否则老浏览器会跳过全部相关规则,连默认 gap 都不应用。正确结构是:
@supports not selector(:has(*)) { .container { gap: 0.5rem; /* 所有浏览器都认的兜底 */ }}.container { display: grid; gap: 0.5rem; /* 默认值,现代浏览器也认 */}.container:has(*:nth-child(2)) { gap: 1rem;}
别指望 @supports 里能写完整逻辑分支——它只负责提供一个安全基线。复杂场景下,JS 注入 class 仍是更可控的 fallback 方案。
实际项目里,最常卡住的不是语法,而是浏览器版本和 DOM 干净度。Chrome 105+ 和 Firefox 121+ 基本稳,Safari 16.4+ 才真正支持 :has(*:nth-child(n)),15.4–16.3 版本对 :nth-last-child() 组合支持极差,别在这段区间内尝试“恰好 N 个”的精确匹配。