:has()可替代多数表单/交互js状态管理,但仅chrome105+、firefox121+、safari15.4+原生支持;旧版浏览器忽略该规则且不降级。

:has() 能直接替代大部分表单/交互类 JS 状态管理,但只在 Chrome 105+、Firefox 121+、Safari 15.4+ 原生可用;旧版浏览器会完全忽略该规则,不触发降级样式。
表单项聚焦与校验状态联动
传统做法是监听 input:focus 和 input:invalid,然后手动给 .field 添加 .focused 或 .error 类。用 :has() 可以省掉所有 JS 绑定:
-
.field:has(input:focus)匹配整个字段容器,无需监听焦点事件 -
.field:has(input:invalid)在表单提交后自动生效,比 JS 校验更及时(浏览器原生校验触发即匹配) - 注意
:invalid必须配合required、type="email"等属性才有效,纯 CSS 不会主动触发校验
复选框控制非相邻兄弟元素
比如导航栏里有个 input[type="checkbox"] 控制侧边栏展开,想让 <main></main> 宽度跟着变 —— 它们之间隔着多层 DOM,~ 或 + 都失效。正确写法是向上找共同祖先再向后选:
-
header:has(nav input:checked) + main:从header出发,确认它内部有被勾选的input,再选紧邻的main - 不能写成
nav input:checked ~ main,因为main不是input的兄弟节点 - 也不能写
input:checked:has(~ main),方向反了::has()必须写在“被影响的元素”前面
全局类存在性检测实现主题切换
不用 JS 监听 document.body.classList,直接靠 CSS 检测任意位置是否存在 .dark 或 .compact 类:
-
body:has(.dark) .btn让所有按钮变深色,无论.dark在页面哪个角落 -
body:has(.compact) .card缩小卡片内边距,哪怕.compact是用户点击后动态插入的<div class="compact"></div> - 避免写
body:has(*.dark)——*会强制浏览器遍历全部子树,性能差;直接写.dark就够了
最易被忽略的是嵌套深度和伪类组合限制::has() 里不能用 :hover、::before,也不支持 :has(:has(...))。它不是万能父选择器,而是“存在性快照”——只对当前渲染帧中已确定的状态起效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











