CSS `:has()` 实战指南:让 CSS 拥有“if 逻辑”
🔮 CSS :has()
实战指南:让 CSS 拥有“if 逻辑”
你是否经常写这样的 JS:
if (element.querySelector('input:checked')) {element.classList.add('active'); }
现在,只需要用
:has()
,你就能让 CSS 自己完成判断。
🧠 什么是 :has()
?
:has()
是一个关系伪类选择器,允许你根据子元素或后代元素的状态,来影响父元素的样式。
基本语法
.parent:has(.child) {background: lightyellow;
}
📌 含有 .child
的 .parent
会被选中。
✅ 实战一:表单错误状态
<div class="form-item"><input type="text" required><span class="error">必填项</span>
</div>
.form-item:has(input:invalid) {border: 1px solid red;
}.form-item:has(input:valid) {border: 1px solid green;
}
✅ 父容器会根据 input 的校验状态自动改变样式,无需 JS。
🧪 实战二:卡片 Hover 触发内部内容变化
<div class="card"><button>操作</button>
</div>
.card:has(:hover) {box-shadow: 0 2px 10px rgba(0,0,0,0.15);
}
📌 当 .card
内任何子元素 hover 时,整个卡片都会响应。
🧪 实战三:替代 JS 的下拉菜单展开
<nav class="menu"><details><summary>更多选项</summary><ul><li>设置</li><li>帮助</li></ul></details>
</nav>
.menu:has(details[open]) {background: #f0f9ff;
}
✅ 当 <details>
展开时,父级菜单会自动改变背景,完全不需要写 JS。
🌟 高级技巧
-
与否定逻辑结合
.list:has(:not(li)) {background: #fee2e2; /* 如果列表为空,标记 */ }
-
与交互伪类结合
.card:has(button:focus) {outline: 2px solid blue; }
-
条件式布局控制
.grid:has(.wide) {grid-template-columns: 2fr 1fr; }
🌐 浏览器支持(2025)
浏览器 | 支持情况 |
---|---|
Chrome 105+ | ✅ |
Edge 105+ | ✅ |
Safari 15.4+ | ✅ |
Firefox | ⚠️ 实验支持(需开启 flag) |
📌 大多数现代浏览器已经支持,Firefox 也即将跟进。
⚠️ 注意事项
- 过度使用
:has()
可能带来性能问题(因为需要浏览器反向查询 DOM) - 尽量用在 UI 交互和组件样式上,而不是大规模列表匹配
- Firefox 用户需注意兼容性,可提供 JS fallback
✨ 一句话总结
:has()
是让 CSS 更加“智能”的关键一步,它让样式具备逻辑判断能力,能大幅减少 JS 样式控制逻辑,是现代 CSS 架构中不可或缺的新利器。