CSS 中 :has() 的强大功能

Avatar of Chris DeMars
Chris DeMars

DigitalOcean 为您的旅程的每个阶段提供云产品。立即开始使用 价值 200 美元的免费积分!

嘿,所有出色的开发者们!在这篇文章中,我们将探索 :has() 在您下一个 Web 项目中的使用。:has() 相对来说比较新,但它在前端社区中获得了流行,因为它能够对 UI 中的各种元素进行控制。让我们来看看这个伪类是什么以及我们如何使用它。

语法

:has() CSS 伪类有助于在元素内部找到并考虑我们要查找的任何内容时设置元素的样式。这就像说,“**如果这个框子里有特定的东西,那么就用这种方式设置这个框子的样式,而且只用这种方式设置样式。**”

:has(<direct-selector>) {
  /* ... */
}

“功能性 :has() CSS 伪类表示一个元素,如果作为参数传递的任何相对选择器在相对于此元素进行锚定时匹配至少一个元素。这个伪类通过接收相对选择器列表作为参数,提供了一种根据参考元素选择父元素或前一个兄弟元素的方法。”

为了更深入地解释,MDN 做得非常完美

样式问题

在过去几年中,我们没有办法使用 CSS 设置父元素的样式,该样式基于该父元素的直接子元素,或者基于另一个元素设置元素的样式。如果我们必须这样做,我们需要使用一些 JavaScript,并根据 HTML 的结构打开和关闭类。:has() 解决了这个问题。


假设您有一个标题级别 1 元素 (h1),它是博客列表页面上文章的标题或类似的东西,然后您有一个标题级别 2 (h2),它紧随其后。这个 h2 可以是文章的副标题。如果这个 h2 存在、很重要并且直接位于 h1 之后,您可能希望让这个 h1 脱颖而出。之前您必须编写一个 JS 函数。

老方法 – JavaScript

const h1Elements = document.querySelectorAll('h1');

h1Elements.forEach((h1) => {
  const h2Sibling = h1.nextElementSibling;
  if (h2Sibling && h2Sibling.tagName.toLowerCase() === 'h2') {
    h1.classList.add('highlight-content');
  }
});

这个 JS 函数正在查找所有在其后面有 h2 的 h1,并应用一个名为 highlight-content 的类,以使 h1 作为重要文章而突出显示。

现代 CSS 出现了新的改进!我们可以在浏览器中完成的事情的能力已经有了很大的进步。现在我们可以利用 CSS 来做一些过去我们必须使用 JavaScript 来做的事情,虽然不是所有的事情,但一些事情。

新方法 – CSS

h1:has(+ h2) {
    color: blue;
}

在上面使用一些 :has()

现在您可以使用 :has() 来实现 JS 函数所做的事情。这个 CSS 检查所有 h1,并使用 兄弟选择器 检查紧随其后的 h2,并向文本添加蓝色。以下是一些 :has() 可能派上用场的情况。

:has 选择器示例 1

HTML

<h1>Lorem, ipsum dolor.</h1>
<h2>Lorem ipsum dolor sit amet.</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eius, odio voluptatibus est vero iste ad?</p>
	
<!-- WITHOUT HAS BELOW -->

<h1>This is a test</h1>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eius, odio voluptatibus est vero iste ad?</p>

CSS

h1:has(+ h2) {
    color: blue;
}
Example of showing :has being used with pseudo classes.

:has 选择器示例 2

很多时候,我们作为 Web 开发人员会操作或使用图像。我们可能会使用 Cloudinary 提供的工具对我们的图像进行各种转换,但通常我们想添加阴影、圆角和标题(不要与 alt 属性中的替代文本混淆)。


下面的示例使用 :has() 来查看图形或图像是否具有 figcaption 元素,如果有,它会应用一些背景和圆角,使图像脱颖而出。

HTML

<section>
  <figure>
    <img src="https://placedog.net/500/280" alt="My aunt sally's dog is a golden retreiver." />
    <figcaption>My Aunt Sally's Doggo</figcaption>
  </figure>
</section>

CSS

figure:has(figcaption) {
  background: #c3baba;
  padding: 0.6rem;
  max-width: 50%;
  border-radius: 5px;
}
Example of :has selector highlighting background an image with an caption vs one that does not.

我能 :has() 它吗?

您可以看到 :has() 在现代浏览器中获得了很好的支持。

这个浏览器支持数据来自 Caniuse,该网站提供了更多详细信息。数字表示浏览器从该版本开始支持该功能。

台式机

ChromeFirefoxIEEdgeSafari
10512110515.4

移动设备/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
12712712715.4

社区中的 :has()

我联系了我在 Twitter 上的网络,看看我的同行们如何在日常工作中使用 :has(),以下是对它的看法。

“我有一个例子是在 @saucedopen 中设置来自第三方包的特定 SVG 的样式,因为我无法直接设置它的样式。”

这是来自 Nick Taylor 的看法,他来自 OpenSauced
svg:has(> #Mail) {
  stroke-width: 1;
}

哈哈,我上次使用它的时候,是在树状视图中构建键盘功能,因此我需要检测兄弟元素的状态和类,但 Firefox 还没有支持它,所以我不得不寻找其他解决方案。🫠

Abbey Perini 来自 Nexcor Food Safety Technologies, Inc.

很高兴看到社区成员如何使用现代 CSS 来解决现实世界中的问题,还要感谢 Abbey 将其用于辅助功能!

需要注意的事项

在使用 :has() 时,有一些关键点需要注意。这些要点参考自 MDN

  • 伪类的特异性将采用其参数中特异性最高的那个选择器。
  • 如果浏览器本身不支持 :has() 伪类,则整个选择器块将失败,除非 :has() 位于宽容的选择器列表中,例如在 :is():where() 中。
  • :has() 伪类不能嵌套在另一个 :has() 中。
  • 伪元素在 `:has()` 中也不算作有效的选择器,而且伪元素也不能作为 `:has()` 的锚点。

结论

利用 CSS 的力量,包括 `:has()` 伪类等高级特性,我们可以打造出色的网页体验。CSS 的优势在于其层叠和特异性……最棒的是,它让我们能够充分发挥其潜力。通过拥抱 CSS 的功能,我们可以推动网页设计和开发向前发展,开拓新的可能性,创造突破性的用户界面。

链接