共计 4274 个字符,预计需要花费 11 分钟才能阅读完成。
本文翻译自 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)