×

CSS::is、:where 和 :has 伪类选择器如何工作

作者:Terry2022.09.04来源:Web前端之家浏览:6891评论:0
关键词:HTML

CSS 选择器允许您在 HTML 文档中按类型、属性或位置选择元素。本教程解释了三个新选项——:is()、:where() 和:has()。

选择器通常用于样式表。以下示例定位所有<p>段落元素并将字体粗细更改为粗体:

p {
  font-weight: bold;
}

您还可以在 JavaScript 中使用选择器来定位 DOM 节点:

  • document.querySelector()返回第一个匹配的 HTML 元素

  • document.querySelectorAll()在类似数组的NodeList中返回所有匹配的 HTML 元素

伪类选择器以 HTML 元素的当前状态为目标。也许最著名的是:hover,它在光标移动到元素上时应用样式,因此它用于突出显示可点击的链接和按钮。其他受欢迎的选项包括:

  • :visited: 匹配访问过的链接

  • :target: 匹配文档 URL 所针对的元素

  • :first-child: 定位第一个子元素

  • :nth-child: 选择特定的子元素

  • :empty: 匹配没有内容或子元素的元素

  • :checked: 匹配一个打开的复选框或单选按钮

  • :blank: 设置空输入字段的样式

  • :enabled:匹配启用的输入字段

  • :disabled:匹配禁用的输入字段

  • :required: 定位一个必需的输入字段

  • :valid: 匹配一个有效的输入字段

  • :invalid: 匹配无效的输入字段

  • :playing:针对正在播放的音频或视频元素

浏览器最近收到了另外三个伪类选择器……

CSS :is 伪类选择器

注意:这最初指定为:matches()and :any(),但:is()已成为 CSS 标准。

您经常需要对多个元素应用相同的样式。例如,<p>段落文本默认为黑色,但出现在 、 或 中时<article><section>灰色<aside>

/* default black */
p {
    color: #000;
  }
 
  /* gray in <article>, <section>, or <aside> */
  article p,
  section p,
  aside p {
    color: #444;
  }


这是一个简单的例子,但更复杂的页面会导致更复杂和冗长的选择器字符串。任何选择器中的语法错误都可能破坏所有元素的样式。

CSS 预处理器,例如 Sass 允许嵌套(这也将用于原生 CSS):

article, section, aside {

    p {
      color: #444;
    }
 
}

这会创建相同的 CSS 代码,减少输入工作量,并可以防止错误。但:

  • 在原生嵌套出现之前,您将需要一个 CSS 构建工具。你可能想使用像 Sass 这样的选项,但这会给一些开发团队带来麻烦。

  • 嵌套可能会导致其他问题。构建深度嵌套的选择器很容易,这些选择器变得越来越难以阅读和输出冗长的 CSS。

:is()提供了一个原生 CSS 解决方案,它完全支持所有现代浏览器(不是 IE):

:is(article, section, aside) p {
    color: #444;
}

单个选择器可以包含任意数量的:is()伪类。例如,以下复杂选择器将绿色文本颜色应用于所有<h1><h2><p>a 的子元素,这些元素<section>具有.primaryor类.secondary且不是 a 的第一个子元素<article>


article section:not(:first-child):is(.primary, .secondary) :is(h1, h2, p) {
    color: green;
}

:is()不需要六个 CSS 选择器的等效代码:


article section.primary:not(:first-child) h1,
article section.primary:not(:first-child) h2,
article section.primary:not(:first-child) p,
article section.secondary:not(:first-child) h1,
article section.secondary:not(:first-child) h2,
article section.secondary:not(:first-child) p {
  color: green;
}

注意:is()不能匹配::before::after伪元素,所以这个示例代码会失败:


/* NOT VALID - selector will not work */
div:is(::before, ::after) {
    display: block;
    content: '';
    width: 1em;
    height: 1em;
    color: blue;
  }

CSS :where 伪类选择器

:where()选择器语法与所有现代浏览器(不是 IE)相同,:is()也受支持。它通常会导致相同的样式。例如:

:where(article, section, aside) p {
    color: #444;
  }

区别在于特异性。特异性是用于确定哪个 CSS 选择器应该覆盖所有其他选择器的算法。在以下示例中,article pp单独更具体,因此 an 中的所有段落元素都<article>将是灰色的:


article p { color: #444; }
p { color: #000; }

在 的情况下:is(),特异性是在其参数中找到的最具体的选择器。在 的情况下:where(),特异性为零。

考虑以下 CSS:

article p {
    color: black;
  }
 
  :is(article, section, aside) p {
    color: red;
  }
 
  :where(article, section, aside) p {
    color: blue;
  }

让我们将此 CSS 应用于以下 HTML:

<article>
  <p>paragraph text</p>
</article>

段落文本将显示为红色,如以下演示所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        article p {
        color: black;
        }

        :is(article, section, aside) p {
        color: red;
        }

        :where(article, section, aside) p {
        color: blue;
        }
    </style>
</head>
<body>
    <article>
        <p>paragraph text</p>
    </article>
</body>
</html>


选择:is()器具有与 相同的特性article p,但它在样式表中较晚出现,因此文本变为红色。有必要同时删除article p:is()选择器以应用蓝色,因为:where()选择器没有任何一个特定。

将使用更多的代码库而:is()不是:where(). 然而,零特异性:where()对于 CSS 重置可能是实用的,它在没有特定样式可用时应用标准样式的基线。通常,重置应用默认字体、颜色、填充和边距。

此 CSS 重置代码将上边距1em应用于<h2>标题,除非它们是元素的第一个子<article>元素:


/* CSS reset */
h2 {
  margin-block-start: 1em;
}

article :first-child {
  margin-block-start: 0;
}

稍后在样式表中尝试设置自定义<h2>上边距无效,因为article :first-child具有更高的特异性:

/* never applied - CSS reset has higher specificity */
h2 {
    margin-block-start: 2em;
  }

您可以使用更高特异性的选择器来解决这个问题,但它的代码更多,对其他开发人员来说不一定很明显。你最终会忘记你为什么需要它:

/* styles now applied */
article h2:first-child {
    margin-block-start: 2em;
  }

您也可以通过应用!important到每种样式来解决问题,但请避免这样做!它使进一步的造型和开发更具挑战性:

/* works but avoid this option! */
h2 {
    margin-block-start: 2em !important;
  }

更好的选择是:where()在您的 CSS 重置中采用零特异性:

/* reset */
:where(h2) {
    margin-block-start: 1em;
  }
 
  :where(article :first-child) {
    margin-block-start: 0;
  }

您现在可以覆盖任何 CSS 重置样式,而不管具体性如何;不需要更多的选择器或!important

/* now works! */
h2 {
    margin-block-start: 2em;
  }

CSS :has 伪类选择器

选择器使用与and:has()类似的语法,但它以包含一组其他元素的元素为目标。例如,下面是为任何包含一个或多个标签的链接添加蓝色、两像素边框的 CSS::is():where()<a><img><section>

/* style the <a> element */
a:has(img, section) {
    border: 2px solid blue;
  }

这是几十年来最激动人心的 CSS 开发!开发人员终于有办法定位父元素了!

难以捉摸的“父选择器”一直是最受欢迎的 CSS 功能之一,但它给浏览器供应商带来了性能复杂性,因此已经有很长一段时间了。简单来说:

  • 浏览器将 CSS 样式应用于页面上绘制的元素。因此,在添加更多子元素时,必须重新绘制整个父元素。

  • 在 JavaScript 中添加、删除或修改元素可能会影响整个页面的样式,直到封闭的<body>.

:has()假设供应商已经解决了性能问题,那么在过去没有 JavaScript 就不可能实现的可能性的引入。例如,<fieldset>当任何必需的内部字段无效时,您可以设置外部表单和以下提交按钮的样式:

/* red border when any required inner field is invalid */
fieldset:has(:required:invalid) {
  border: 3px solid red;
}

/* change submit button style when invalid */
fieldset:has(:required:invalid) + button[type='submit'] {
  opacity: 0.2;
  cursor: not-allowed;
}

image.png

此示例添加包含子菜单项列表的导航链接子菜单指示器:

/* display sub-menu indicator */
nav li:has(ol, ul) a::after {
    display: inlne-block;
    content: ">";
  }

或者,也许您可以添加调试样式,例如突出显示<figure>没有内部的所有元素img

/* where's my image?! */
figure:not(:has(img)) {
    border: 3px solid red;
  }

在你进入你的编辑器并重构你的 CSS 代码库之前,请注意它:has()是新的,并且支持比 for:is():where(). 它可在Safari 15.4+和 Chrome 101+ 中使用,但应在 2023 年广泛使用。

选择器摘要

和伪类选择器简化了 CSS 语法:is():where()您对嵌套和 CSS 预处理器的需求将减少(尽管这些工具提供了其他好处,例如部分、循环和缩小)。

:has()更具革命性和令人兴奋。家长选择将迅速流行,我们将忘记黑暗时期!:has()当所有现代浏览器都可用时,我们将发布完整的教程。


您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://jiangweishan.com/article/htmlcss20220904.html

网友评论文明上网理性发言 已有0人参与

发表评论: