CSS 新特性 :has() 选择器,不需要 JS 也能实现神奇交互
以前是无法直接用 CSS 来“选择父元素”的,而 :has() 选择器的出现,刚好改变了这一现状。
下面,我们一起看看:has()选择器是如何使用的吧。
一、介绍
:has()其实就是一个伪类选择器,它可以选择包含特定子级元素的元素。
听起来可能有点绕,我们直接看它的语法吧:
/* 选择“包含 img 子元素”的 article 元素 */
article:has(img) {}
/* 选择“直接子元素是 figcaption”的 figure 元素 */
figure:has(> figcaption) {}
/* 选择“包含空的 p 元素”的 div */
div:has(p:empty) {}
你也可以这样理解,它就是选择“满足特定条件”的父级元素,两个重点:
-
选择的是父元素; -
子元素只是作为条件。
为什么说它强大?
因为它打破了过去“CSS 只能向下选择”的限制,能够通过子元素的状态来改变父级元素的样式。
二、实战案例
下面看两个比较常见的案例吧。
1️⃣ 卡片高亮效果
假如有一个卡片,需要实现当“鼠标悬停某个子元素时”,整个卡片进行高亮。
<!-- 一个简单的卡片 -->
<section class="card">
<h2>卡片标题</h2>
<p>这是一段描述文字...</p>
</section>
.card {
padding: 8px 16px;
width: 300px;
border: 1px solid #ddd;
border-radius: 16px;
}
/* 当悬停在 p 元素上时,整个卡片高亮 */
.card:has(p:hover) {
border-color: #007bfe;
box-shadow: 0 4px 12px rgba(0, 121, 251, 0.3);
}
👉 最终效果:只有鼠标放在<p>标签上时,卡片才会高亮。

2️⃣ 输入框校验报错提示
这个场景大家应该都遇到过,当表单项输入报错时,需要对整个表单项区域做一个视觉反馈效果。
<div class="form-item">
<label for="email">邮箱地址:</label>
<input type="email" id="email" required>
<span class="hint">请输入有效的邮箱地址</span>
</div>
.hint {
display: none;
color: red;
font-size: 14px;
}
/* 当输入框“验证失败”时,显示提示文字 */
.form-item:has(input:invalid:focus) .hint {
display: block;
}
/* “验证失败”,高亮整个表单项区域 */
.form-item:has(input:invalid:focus) {
padding: 16px;
background-color: #fef6f8;
border-left: 3px solid red;
}
👉 效果预览:

在以前,用纯 CSS 就无法实现以上这两个案例,必须借助 JS 的能力来完成,现在有了:has()之后,实现起来就简单多了。
三、高级技巧
👉 与相邻选择器组合:
/* 选择后面跟着 <hr> 的 <section> */
section:has(+ hr) { margin-bottom: 0; }
以前,相邻选择器只能选择相邻的“下一个”元素,现在能够实现选择相邻的“上一个” 元素了。
👉 与兄弟选择器组合:
/* 选择除了最后一个子元素以外的所有 .list-item */
.list-item:has(~ .list-item) { border-bottom: 1px solid #eee; }
当然,如果你有更复杂的需求,你也可以与任何选择器组合,从而可以创造出非常精细的样式控制。
四、浏览器支持情况
根据caniuse上面的数据来看,基本上,2022 年之后的主流浏览器都已支持。

当下建议:如果对兼容性比较敏感或者是比较重要的功能,需要谨慎使用;如果只是作为视觉体验上的提升,那么还是很值得一试的。
五、总结
随着 CSS 的不断发展,各种新功能也逐渐推出。以前很多都需要借助 JS 才能实现的能力,现在直接用 CSS 本身就能够完美的实现了。
不需要借助 JS 之后,它也让我们编写的代码更简洁且容易维护。
来源:前端星河
THE END





