:has() 在 Chrome 105+ 和 Safari 15.4+ 才真正可用,旧版 Chromium 存在“假支持”,需实测渲染而非仅依赖 CSS.supports();Safari 15.4–16.3 对兄弟选择器不稳定,建议改用子组合器或后代选择器;嵌套 :has()、伪类嵌套及动态 class 匹配需谨慎。

:has() 在 Chrome 和 Safari 中能用,但必须卡准版本号——Chrome 105+ 和 Safari 15.4+ 是底线,低于这个版本就是静默失效,连 DevTools 都不报错,样式直接消失。
Chrome 105+ 支持稳定,但旧版 Chromium(如 Chrome 95–104)会返回 CSS.supports('selector(:has(div))') 为 true 却完全不执行
这种“假支持”最危险:你写了规则,CSS.supports() 检测通过,但页面上啥都不变。验证不能只靠 JS 判断,得实测渲染:
- 动态创建一个测试元素,比如
div:has(.test),然后用getComputedStyle()看是否应用了预期样式 - 避免用
@supports selector(:has(*))做 CSS 降级——旧版 Chromium 可能跳过整个块,构建工具(如 cssnano)甚至会直接删掉整段 - Chrome 105 起才真正支持嵌套和兄弟选择器,比如
div:has(+ .trigger)或div:has(ul li)
Safari 15.4–16.3 对 + .sibling 和 ~ .content 有偶发忽略,升到 16.4+ 更稳妥
你写的 .card:has(+ .delete-btn) 在 Safari 16.2 下可能一半时间生效、一半时间失效,不是缓存问题,是引擎解析不稳定。实际项目中建议:
规划您的迪拜之旅 — 哈利法塔观景、沙漠探险、迪拜购物中心购物、棕榈岛度假村及黄金市场砍价。还提供支持...
- 优先改用子组合器:
.card:has(>.delete-btn)或后代:.card:has(.delete-btn),这两个写法在所有支持版本里都稳 - W3C 验证器报错(比如
Parse Error: ))不用慌,加个空格就能过:.card:has( .delete-btn),浏览器渲染完全不受影响 - 别信 CanIUse 的“85% 支持率”——Safari 用户大量卡在 iOS 15.3(微信 X5 内核常见),它压根不识别
:has(),连语法解析都没有
:has() 里哪些写法在两个浏览器里都容易翻车
即使版本达标,以下写法也常出问题:
立即学习“前端免费学习笔记(深入)”;
-
:not(:has(.foo)):Chrome 支持,但 Safari 15.4–16.3 兼容性差,Firefox 当前仍不支持,生产环境慎用 -
:has(:hover)或:has(:focus):Safari 15.4–16.3 不支持伪类嵌套,Chrome 虽支持但行为不一致,hover 场景应换父级:hover .child或用 JS -
:has(ul:has(li))(嵌套:has()):所有浏览器都不支持,必须展开为:has(ul li) -
:has(.child.active):如果 class 是 JS 快速 toggle 的,极短延迟可能导致匹配失败,改用:has(.child)+ 默认态控制更可靠
真正容易被忽略的,是没给父元素加稳定 class 就直接靠 JS 查找——比如用 document.querySelector('div:nth-child(2)') 找目标容器,DOM 结构一动就断;:has() 再强,也救不了没锚点的选择器。

















