Firefox 120及更早版本完全不支持:has(),解析器静默丢弃整条CSS规则且querySelector抛错;可靠检测需组合验证querySelecto执行结果与样式实际生效情况。

:has() 在 Firefox 旧版(120 及更早)中根本不会生效,不是“不触发样式”,而是浏览器解析器直接跳过整条规则——连 DevTools → Styles 面板里都看不到它。Firefox 直到 121 版本才默认启用该特性,此前即使手动开启 layout.css.has-selector.enabled,document.querySelector('div:has(.child)') 仍会抛出 DOMException: "is not a valid selector"。
Firefox 120 及更早版本会静默丢弃 :has() 规则
这不是兼容性 bug,是语法层面未实现。CSS 解析器遇到不认识的伪类,整条声明(选择器 + 大括号内所有样式)都会被忽略,不报错、不警告、不渲染。构建工具如 cssnano 更激进:检测到不支持语法,直接从输出 CSS 中删掉整条规则,连降级机会都不留。
-
document.querySelector('div:has(.child)')在 Firefox 120 中必然抛错,不是返回null -
CSS.supports('selector(:has(div))')在 Firefox 120 中返回false,但别只信这个——Chromium 90–104 有假阳性,返回true却完全不应用样式 - 不要用
@supports selector(:has(*)) { ... }包裹整段 CSS 做降级开关,iOS 15.3 及更早连这个@supports语法都不认,整块被跳过
真正可靠的运行时检测必须同时验证两件事
只查 CSS.supports 或只查 querySelector 都不够。必须组合判断:
- 执行
const el = document.querySelector('body:has(div)');—— 若抛错或返回null,说明不支持 - 在页面上找一个已知含子元素的容器(比如
<div class="test-parent"> <p>child</p><div class="aritcle_card flexRow"> <div class="artcardd flexRow"> <a class="aritcle_card_img" href="/xiazai/code/12093" title="CSS婚礼策划服务机构宣传网站模板"><img src="https://img.php.cn/upload/webcode/000/000/018/178607072210981.jpg" alt="CSS婚礼策划服务机构宣传网站模板" ></a> <div class="aritcle_card_info flexColumn"> <a href="/xiazai/code/12093" title="CSS婚礼策划服务机构宣传网站模板">CSS婚礼策划服务机构宣传网站模板</a> <p>CSS婚礼策划服务机构宣传网站模板是一款适合提供婚礼策划和婚庆服务机构宣传网站模板下载。提示:本模板调用到谷歌字体库,可能会出现页面打开比较缓慢。</p> </div> <a href="/xiazai/code/12093" title="CSS婚礼策划服务机构宣传网站模板" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> <p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p> </div>),给它写.test-parent:has(p) { background: lime; } - 用 JS 检查该元素是否真实渲染了
background: lime:getComputedStyle(el).backgroundColor === 'rgb(192, 255, 192)' - 只有两个条件同时满足,才能确认
:has()真可用
别依赖 :not(:has()) 做降级,Firefox 完全不认
:not(:has(.btn)) 虽然语法合法,但 Firefox 当前最新稳定版(2026 年 7 月)仍不支持该组合。整条 CSS 规则会被静默丢弃,DevTools 里根本看不到它。Safari 15.4–16.3 也有偶发忽略。你写的不是“降级”,是“对部分用户彻底失效”。
- 改用正向标记:
.card定义默认样式,.card:has(.delete-btn)只覆盖需要调整的部分 - 服务端/构建时注入类名,比如
<div class="card card--has-delete">,CSS 写成 <code>.card--has-delete { ... } - 轻量 JS 补位(加
CSS.supports检测):if (!CSS.supports('selector(:has(*))')) { document.querySelectorAll('.card').forEach(el => { if (!el.matches(':has(.btn)')) el.classList.add('card--no-btn'); }); } - 引入后,
document.querySelectorAll('header:has(+ div.content)')在 Firefox 120 也能跑通 - 但它不解决样式层问题:CSS 文件里的
:has()规则依然被浏览器跳过,所以必须保留兜底类名(如.form.has-error) - 注意 polyfill 不兼容 IE 和 Android 4.4 WebView,但这两者已基本退出主流场景(截至 2026 年 5 月)
polyfill-pseudoclass-has 是目前唯一生产可用的 JS 方案
PostCSS 类工具无法 polyfill :has()——它依赖 DOM 实时结构,静态构建时根本无法模拟。而 polyfill-pseudoclass-has 不改写 CSS,只增强原生方法:querySelector、querySelectorAll、matches、closest 全部支持 :has() 语法,且按需计算、性能可控。
最易被忽略的一点:所谓“85% 全球支持率”来自 CanIUse 的加权统计,但 B 端系统、银行内网、政务平台等场景中,大量终端卡在 Chrome 70–90 区间,:has() 在那里就是无效声明——你得靠后端输出语义 class 或轻量 MutationObserver 来兜底,而不是指望浏览器自动升级。

















