CSS新特性探索:深入了解“has()”选择器

随着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()选择器的应用。

  1. 高亮包含特定子元素的列表项
css 复制代码
ul:has(> li.active) {
  background-color: lightblue;
}

这个示例中,所有包含有类名为active的列表项的ul元素都会被选中,并且背景颜色将变为浅蓝色。

  1. 样式化包含图片的段落
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()选择器有了更深入的了解,并能够在实际项目中灵活应用这一新功能,为页面的样式和结构提供更多可能性。

参考

developer.mozilla.org/zh-CN/docs/...

相关推荐
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax