:has() 仅在 chrome 105+、firefox 121+、safari 15.4+(macos monterey 及更新系统)和 ios safari 15.4+ 中真正支持,旧版 safari 和 ie 不支持,且构建工具、ssr、语法错误及性能开销均需谨慎处理。

:has() 是目前唯一能在 CSS 中“向上选择”的机制,但它有明确的浏览器支持边界和使用限制——别指望它在旧版 Safari 或 IE 里工作,也别把它当 jQuery 的 $().parent() 那样随意用。
哪些浏览器真正支持 :has()?
Chrome 105+、Firefox 121+、Safari 15.4+(仅限 macOS Monterey 及更新系统)才启用该伪类。iOS Safari 15.4+ 也支持,但早期 iOS 版本(如 iOS 15.0–15.3)即使标称“支持”也会静默失败。
- 测试时务必用
document.querySelector(':has(*)')在控制台手动验证,而不是只看 caniuse 数据 - Webpack/Vite 构建中若启用了 CSS 压缩(如 cssnano),某些版本会直接删掉含
:has()的规则——需升级到 cssnano v6.0+ 并显式开启discardUnused: false - Next.js 13+ App Router 默认 SSR 渲染,而
:has()在服务端不生效,会导致首屏样式丢失;必须配合useEffect或dynamic(..., { ssr: false })降级处理
:has() 的语法边界与常见失效场景
它只接受简单选择器组合,不支持复杂嵌套或伪元素引用。一旦写错,整条规则会被浏览器忽略(无报错提示)。
- ✅ 正确:
article:has(> .featured)、div:has(p:first-child)、ul:has(li.active) - ❌ 失效:
section:has(.item::before)(伪元素不可选)、nav:has(> a[href^="https"] + a)(相邻兄弟选择器在:has()内无效)、div:has(* > span)(通配符开头不被允许) - ⚠️ 注意:
:has()内部的:hover、:focus等交互伪类仅在支持它的浏览器中动态响应,且可能触发重排——避免在滚动容器内高频使用
替代方案:当 :has() 不可用时怎么绕过?
没有 JS 就无法真正“反向选择”,但可通过结构微调 + 属性标记降低侵入性。
- 给父元素加 data 属性:
<article data-has-featured="true">...</article>,再用article[data-has-featured]选中 - 利用 CSS 自定义属性传递状态:
article { --has-featured: 0; } article .featured { --has-featured: 1; },然后用article:has(.featured) { --has-featured: 1; }+article[style*="--has-featured: 1"]组合兜底(不推荐,维护成本高) - 最稳方案:用 JS 监听子元素变动,动态添加 class:
const observer = new MutationObserver(() => el.classList.toggle('has-featured', !!el.querySelector('.featured')));
真正麻烦的不是语法,而是 :has() 触发的样式计算开销——它会让浏览器对每个候选父元素都执行子树遍历。如果页面有上百个 div:has(button),滚动时卡顿会立刻出现。别为了少写几行 JS,把性能隐患埋进 CSS 里。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











