本文翻译自 How the CSS :is, :where and :has Pseudo-class Selectors Work,作者:Craig Buckler 略有删改

CSS 选择器容许咱们按HTML文档中的类型、属性或地位抉择元素。本教程介绍了三个新选项:is():where():has()

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

p {  font-weight: bold;}

你也能够在新版的JavaScript中应用选择器来定位DOM节点:

  • document.querySelector() 返回第一个匹配的HTML元素
  • document.querySelectorAll() 返回所有匹配的HTML元素 NodeList 节点列表

伪类选择器基于HTML元素的以后状态来定位它们。用到比拟多的是:hover,它在光标挪动到元素上时利用款式,因而它用于突出显示可单击的链接和按钮。还有如下伪类选择器供咱们应用:

  • :visited:匹配拜访过的链接
  • :target:匹配文档有URL指向的元素
  • :first-child:选中指标元素的第一个子元素
  • :nth-child:抉择特定的子元素
  • :empty:匹配一个没有内容或子元素的元素
  • :checked:匹配已关上的复选框或单选按钮
  • :blank:设置未输出字段的状况
  • :enabled:匹配已启用的输出字段时
  • :disabled:匹配禁用的输出字段时
  • :required:针对必填输出字段时
  • :valid:匹配无效的输出字段时
  • :invalid:匹配有效的输出字段时
  • :playing:针对播放的音频或视频元素

浏览器最近又减少了三个伪类选择器。

:is伪类选择器

通常须要将雷同的款式利用于多个元素。例如,<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,容许嵌套应用:

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

最终也将创立雷同的CSS代码,缩小开发工作量,并能够避免谬误。然而:

  • 须要一个CSS构建工具。比方Sass这样的预处理器,但这可能会给某些开发团队带来复杂性。
  • 嵌套可能会导致其余问题。构建深度嵌套的选择器很容易,而这些选择器越来越难以读取和输入简短的CSS。

:is()提供了一个原生的CSS解决方案,在所有古代浏览器(不包含IE)中都有齐全反对:

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

单个选择器能够蕴含任意数量的:is()伪类。例如,上面的简单选择器将绿色文本色彩利用于所有<h1><h2><p>元素,这些元素是具备<section>.primary类的.secondary的子元素,并且不是<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伪元素,因而以下示例代码将生效:

div:is(::before, ::after) {  display: block;  content: '';  width: 1em;  height: 1em;  color: blue;}

:where伪类选择器

:where()选择器语法与:is()雷同,并且在所有古代浏览器(不包含IE)中都反对。这通常会导致雷同的款式。例如:

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

区别在于特异性。特异性是用于确定哪个CSS选择器应该笼罩所有其余CSS选择器的算法。在上面的例子中,article p比独自的p更具体,所以<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>

最终段落文本将显示为红色,如上面的CodePen演示所示。

:is()选择器与article p有着雷同的个性,然而它在样式表中的前面呈现,所以文本变成红色。如果要利用蓝色,必须同时删除article p:is()选择器,因为:where()选择器比照这两个选择器都不那么具体。

更多的代码库将应用√而不是:where()。然而,:where()的零特异性对于CSS重置可能是实用的,当没有特定的款式可用时,CSS重置利用规范款式的基线。通常,重置会利用默认字体、色彩、填充和边距。

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

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

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

h2 {  margin-block-start: 2em;}

能够应用更高特异性的选择器来修复这个问题,但它须要更多的代码,而且对其余开发人员来说并不一定是不言而喻的。你最终会遗记你为什么须要它:

article h2:first-child {  margin-block-start: 2em;}

您也能够通过将!important利用到每种款式来解决问题,但请防止这样做!它使得进一步的造型和开发更具挑战性:

h2 {  margin-block-start: 2em !important;}

一个更好的抉择是在CSS重置中采纳:where()的零特异性:

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

你当初能够笼罩任何CSS重置款式,而不论它的特殊性,也不须要更多的选择器或!important

h2 {  margin-block-start: 2em;}

:has伪类选择器

:has()选择器应用与:is():where()类似的语法,但它的指标是蕴含一组其余元素的元素。例如,上面的CSS用于为任何蕴含一个或多个<a><img>标签的<section>链接增加一个蓝色的两像素边框:

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;}

此示例增加蕴含子菜单项列表的导航链接子菜单批示符:

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

或者你能够增加调试格调,比方突出显示所有的<figure>元素,而不带外部的img

figure:not(:has(img)) {  border: 3px solid red;}

在你进入你的编辑器并重构你的CSS代码库之前,请留神:has()是新的,反对比:is():where()更无限。它能够在Safari 15.4+和Chrome 101+中应用,但它应该在2023年之前宽泛应用。

最初

:is():where()伪类选择器简化了CSS语法。您将不须要嵌套和CSS预处理器(只管这些工具提供了其余益处,如局部、循环和放大)。

:has()更具革命性和令人兴奋。父级抉择将迅速流行起来,咱们将遗记过来的黑暗时代!

看完本文如果感觉有用,记得点个赞反对,珍藏起来说不定哪天就用上啦~

专一前端开发,分享前端相干技术干货,公众号:南城大前端(ID: nanchengfe)