不能直接用 :has(input:checked) 改父背景,除非接受 Chrome 105+/Firefox 121+/Safari 15.4+ 的兼容性断层,并排除 disabled、portal/shadow DOM、伪类嵌套等失效因素。

不能直接用 :has(input:checked) 改父背景,除非你明确接受 Chrome 105+ / Firefox 121+ / Safari 15.4+ 的兼容性断层,且已排除焦点传播、DOM 结构、伪类嵌套等常见失效点。
为什么 :has(input:checked) 常常没反应
写完样式却看不到背景变化,大概率不是语法错,而是底层条件不满足:
-
input[type="checkbox"]默认不可聚焦,:checked是状态伪类,但:has()不关心它是否“能被 tab 到”,只看 DOM 中是否存在匹配节点;不过若 checkbox 被disabled或包裹在fieldset[disabled]里,:checked本身就不生效 →:has()自然不匹配 -
:has()匹配的是“真实存在的后代”,不是渲染结果。React/Vue 组件中若把 checkbox 渲染进portal或 shadow DOM,:has()就完全看不见它 - 写了
.form:has(input:checked),但实际结构是.form > div > div > input—— 没问题,:has()支持任意深度后代;但如果用了.form:has(> input:checked),就要求必须是直接子元素,否则失效 - Safari 15.4+ 才支持
:has(),且不支持在@keyframes或transition中使用;旧版 Safari 或未开启 flag 的 Firefox 会直接忽略整条规则,连降级样式都不触发
更稳妥的替代方案::focus-within 与结构微调
如果目标只是“用户操作后让父容器视觉反馈”,:focus-within 往往比 :has(input:checked) 更可靠、更轻量:
-
:focus-within是原生支持多年的伪类(Chrome 60+、Firefox 61+、Safari 15.4+),无需启用 flag,也不受 shadow DOM 隔离影响 - 它不要求子元素是
input:checked,只要任意可聚焦后代获得焦点(包括input、textarea、button、带tabindex的div)就触发 - 示例:想在表单获得焦点时高亮整个区域,直接写
form:focus-within { background: #e6f7ff; },哪怕input套了五层div也生效 - 若硬要响应
checked状态,可配合tabindex让 checkbox 可聚焦,再用:focus-within间接捕获 —— 但这属于 hack,不如用 JS 或改用:has()(见下一条)
真要用 :has() 响应 checked,注意这三点
确认浏览器支持后,以下写法才可能生效:
立即学习“前端免费学习笔记(深入)”;
- 确保 checkbox 是普通 DOM 节点,没被 portal/shadow DOM 隔离;检查 DevTools 的 Elements 面板,确认
input:checked确实存在且状态为 true - 结构宽松写法(推荐):
.card:has(input[type="checkbox"]:checked)—— 不限制层级,不依赖兄弟关系,只要 card 内有任何一个选中的 checkbox 就匹配 - 避免组合无效伪类:
:has(input:checked:focus)是错的,:checked和:focus不会同时成立(checkbox 选中后通常立即失焦);:has(::before)或:has(:hover)也非法,:has()参数只能是能生成真实节点的选择器 - 性能提示:若页面有大量
:has()规则,或 checkbox 频繁切换,某些低端 Android 设备可能出现重绘延迟;建议仅用于关键交互反馈,非全屏动态布局
真正难的不是写对那行 CSS,而是判断当前项目是否值得为 :has() 承担兼容性成本和调试时间 —— 如果目标用户中仍有 >5% 使用 Safari 15.3 或旧版 Chrome,就别把它当主逻辑;如果只是给管理后台加个视觉提示,那 :has() 现在已经够用了。


















