浏览器不支持 :has() 时规则会被静默丢弃,需用 css.supports('selector(:has(*))') 检测;仅 chrome 105+、firefox 121+、safari 15.4+ 默认支持;括号内须匹配真实 dom 元素或状态,伪元素、动态伪类等不可靠。

浏览器不支持 :has() 时根本看不到规则
写了 .form:has(input:invalid) 却没反应?先看 DevTools 的 Styles 面板里这条规则是否存在——如果压根没出现,说明浏览器直接忽略语法,不是你写错了。Chrome 105+、Firefox 121+、Safari 15.4+ 才默认支持;iOS 15.3 及更早的 Safari、旧版 Electron(如 VS Code 1.7x)、Firefox 120 及更早(未开启 layout.css.has-selector.enabled)都会静默丢弃整条规则。
检测是否可用的最简方式是运行:CSS.supports('selector(:has(*))') 返回 true 才能放心用。返回 false 就得切 JS 降级方案,比如监听 input 的 invalid 事件后给父元素加 data-invalid 类。
:has() 括号里只能塞“真能匹配到节点”的选择器
伪元素(::before)、动态伪类(:hover、:focus、:focus-within)和结构伪类(:empty、:nth-child(2))在 :has() 内部要么非法,要么行为不可靠:
-
div:has(::before)→ 语法错误,伪元素不生成真实 DOM 节点 -
section:has(div:hover)→ 大概率失效,<div> 默认不可交互,Safari 尤其敏感 <li> <code>.card:has(.child:empty)→ 永远不匹配,因为:has()自身存在已让父元素“非空” - 写了
.form:has([data-valid=true])却无效 → 正确写法是[data-valid="true"],属性值必须加引号 - JS 里只执行了
el.dataset.valid = 'true'→ 这不会设置 DOM attribute,得用el.setAttribute('data-valid', 'true') - 用了
for/id分离的<label for="cb"></label><input id="cb" type="checkbox">→label:has(input:checked)不会生效,:has()不跨 ID 关联,必须写成<label><input type="checkbox"></label>结构 -
.card { height: auto !important; }会挡住.card:has(.loading) { height: 100px; },因为!important权重更高 - 在 Shadow DOM 内部写
:has()→ 无法匹配 light DOM 中的子元素,也不触发外部父容器样式变化;需透传 class 或用::slotted() - 写
body:has(.modal-open)或嵌套三层以上(如.list:has(.item:has(.badge:has(span))))→ 浏览器需向上遍历大量节点,滚动或动画场景下明显卡顿
真正安全的组合只有这些:label:has(input:checked)、form:has(input:invalid)、details:has([open])、article:has(.comment.error)、div:has([data-loaded="true"]) —— 关键是括号内必须指向一个**真实存在于 DOM 上的元素或状态**。
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
属性值不加引号、JS 改 dataset 都会导致匹配失败
:has() 匹配的是 DOM attribute,不是 JS property。常见坑点:
父元素样式被覆盖、Shadow DOM 隔离、性能拖慢都是隐形杀手
就算语法正确、浏览器支持,也可能白写:
最易被忽略的是:动态插入的子元素(如通过 innerHTML 添加)的状态变化能即时触发 :has(),但若父元素本身是 JS 新建且尚未 appendChild 到 DOM,那这条规则就永远不会生效——它不预编译,只作用于已挂载的节点。










