随着CSS的不断演进,新的选择器和功能不断涌现。:has()
选择器是CSS的一个新特性,它允许开发者选择包含指定子元素的父元素。本文将深入探讨:has()
选择器的语法、用法以及实际应用场景,帮助读者更好地理解和应用这一新功能。
引言
CSS的发展一直在不断推动着Web开发的进步。随着新的CSS规范的发布,开发者们可以使用更多的选择器和功能来控制和美化页面的样式。其中,:has()
选择器是一个备受关注的新特性,它为开发者提供了一种选择包含特定子元素的父元素的简便方法。
什么是:has()
选择器?
先来看看MDN是怎么解释的
CSS 函数式伪类 :has()
表示一个元素,如果作为参数传递的任何相对选择器在锚定到该元素时,至少匹配一个元素。这个伪类通过把可容错相对选择器列表作为参数,提供了一种针对引用元素选择父元素或者先前的兄弟元素的方法。
css
h1:has(+ p) {
margin-bottom: 0;
}
这段 CSS 代码表示选择所有包含紧邻的 <p>
元素的 <h1>
元素,并将它们的下边距(margin-bottom
)设为零。
语法
:has()
选择器是CSS的一个新功能,它允许开发者选择包含指定子元素的父元素。这个选择器的语法如下:
css
:has(selector) {
/* styles */
}
其中,selector
是一个CSS选择器,用于指定要查找的子元素。
相对选择器列表参数是可容错的。通常在 CSS 中,选择器列表中的某个选择器无效时,那么整个列表则被视为无效。当 :has()
选择器列表中的一个选择器无法解析时,不正确或不受支持的选择器将被忽略,而其他的则将被正常使用。
:has()
伪类不能被嵌套在另一个 :has()
内。另外,伪元素不是 :has()
内的有效选择器。这是因为许多伪元素基于其祖先的样式有条件地存在,如果允许通过 :has()
查询这些伪元素可能导致循环查询。虽然 :has()
和伪元素在 :has()
中是无效的选择器,但由于选择器列表是可容错的,它们将只是被忽略。选择器将不会失效。
示例应用
在过去的几年里,我们在使用 CSS 设计父元素样式时,通常无法直接根据父元素的直接子元素或者基于另一个元素的状态来进行操作。在这种情况下,我们通常需要借助 JavaScript 来根据 HTML 结构来添加或移除类,从而实现样式的控制。然而,现在有了:has()
选择器,它为我们提供了一种更便捷的方式来解决这个问题。
例如要突出显示一个页面上的标题(h1元素),假设博客列表页面上的帖子或类似性质的内容的标题,如果紧随其后有一个重要的副标题(h2元素),如果h2
存在、并且紧接在 h1
后面,这种情况下想让h1
样式特殊处理,我们通常需要编写JavaScript函数来实现。但现在有了:has()
选择器,我们可以用更简洁的CSS规则来达到同样的效果。
之前的实现方式
javascript
const h1Elements = document.querySelectorAll('h1');
h1Elements.forEach((h1) => {
const h2Sibling = h1.nextElementSibling;
if (h2Sibling && h2Sibling.tagName.toLowerCase() === 'h2') {
h1.classList.add('highlight-content');
}
});
有了:has()
选择器之后
css
h1:has(+ h2) {
color: blue;
}
一行csss就搞定了,是不是简单多了。
下面让我们通过一些示例来深入了解:has()
选择器的应用。
- 高亮包含特定子元素的列表项:
css
ul:has(> li.active) {
background-color: lightblue;
}
这个示例中,所有包含有类名为active
的列表项的ul
元素都会被选中,并且背景颜色将变为浅蓝色。
- 样式化包含图片的段落:
css
p:has(> img) {
border: 2px solid black;
}
这个示例中,所有包含图片的段落元素都会被选中,并且添加了一个黑色的边框。
实际应用场景
:has()
选择器在实际的Web开发中有着广泛的应用场景,特别是在需要根据子元素来样式化父元素的情况下,非常有用。比如,可以用它来优化导航菜单、样式化包含特定内容的段落、或者根据内容来样式化列表等等。
通常在业务场景中,针对某个元素,如果有标题,或者有特定元素,父元素的样式会发生变化。
下面的示例用:has()
来查看图片是否具有Figcaption元素(标题介绍),如果有,它会加背景和边框使他上看去更明显。
html
html
<section>
<figure>
<img width="200" src="https://img-baofun.zhhainiao.com/fs/30d21f55142ed452db715c50bada6bcb.jpg" alt="鲜花" />
<figcaption>这是鲜花</figcaption>
</figure>
</section>
<section>
<figure>
<img width="200" src="https://img-baofun.zhhainiao.com/fs/30d21f55142ed452db715c50bada6bcb.jpg" alt="鲜花" />
</figure>
</section>
css
figure:has(figcaption) {
background: #dedede;
padding: 10px;
width: 200px;
border-radius: 5px;
}
在实际业务场景中,我们是不是经常遇到更改网站的主题颜色,下面让我们看看用:has()
怎么轻松实现吧。
假设在页面上有个标签供用户选择主题颜色, <select> <option value="light">浅色模式</option> <option value="dark">深色模式</option> </select> 我们可以在元素上使用:has(),并检查的selected,这样,如果包含某个值,我们可以用不同的颜色值更新css,来更改当前的主题颜色。
css
body:has(option[value="dark"]:checked) {
--primary-color: #e43;
--surface-color: #1b1b1b;
--text-color: #eee;
}
body:has(option[value="light"]:checked) {
--primary-color: #6366f1;
--surface-color: #fff;
--body-color: #eee;
--text-color: #333;
}
来看看效果吧。
看到这里你脑海中是不是也想到很多应用场景了?还有很多效果可以实现,例如,当表单项出错的时候,将form高亮;根据子元素的数量设置元素样式等等,更多场景等你来探索。
注意事项
-
如果一个浏览器中不支持
:has()
伪类本身,则整个选择器块将失效(除非:has()
本身位于一个可容错选择器列表中,比如在:is()
或:where()
中)。来看一下和
:is()
一起使用:css:is(h1, h2, h3, h4, h5, h6):has(a) { color: blue; }
这段 CSS 代码的意思是,选择页面中所有的
<h1>
到<h6>
元素中,如果它们包含至少一个<a>
元素,则将它们的文字颜色设置为蓝色。
还可以将 :is()
作为参数传递给 :has()
css
:is(h1, h2, h3, h4, h5, h6):has(a) {
color: blue;
}
这段 CSS 代码的意思是,选择页面中所有的 <h1>
到 <h6>
元素中,如果它 们包含至少一个 <a>
元素或者具有类名为 .link
的元素,则将它们的文字颜 色设置为蓝色。
-
:has()
伪类不能被嵌套在另一个:has()
内;css.header-group:has(.subtitle:has(h2)) { /* Invalid! */ }
上面这段代码将创建一个无限循环。这样的选择器语法是无法生效的。
可以改成链式的方式:
css.header-group:has(h2):has(.subtitle) h2 { margin-bottom: 10px; color: blue; }
链式写法类似于
&&
逻辑运算,两个条件必须匹配才能使样式规则生效。上面这个代码将选择出class名为header-group并且包含h2以及包含class为subtitle的元素。 -
伪元素不是
:has()
内的有效选择器。这是因为许多伪元素基于其祖先的样式有条件地存在,如果允许通过:has()
查询这些伪元素可能导致循环查询;
兼容性
尽管:has()
选择器为我们提供了很大的便利,但目前并未得到所有主流浏览器的完全支持。因此,在使用时需要谨慎考虑兼容性,并根据实际情况进行决策。附上一张目前支持的浏览器的图片。
结论
:has()
选择器是CSS的一个新特性,它为开发者提供了一种选择包含指定子元素的父元素的便捷方法。通过本文的介绍,相信大家已经对:has()
选择器有了更深入的了解,并能够在实际项目中灵活应用这一新功能,为页面的样式和结构提供更多可能性。