作为"父选择器"的先驱,:has()
伪类的范围远比仅仅为元素的祖先设置样式大得多。凭借其在 Safari 15.4+ 和 Chromium 105+ 中的可用性,以及在 Firefox 中的标志,现在是您熟悉:has()
其用例的好时机。
作为一个伪类,它的基本功能:has()
是设置它所附加的元素的样式------也就是所谓的"目标"元素。这类似于其他伪类,如:hover
or :active
,a:hover
旨在为<a>
处于活动状态的元素设置样式。
然而,:has()
也类似于:is()
, :where()
, 和:not()
,因为它接受括号内的相对选择器列表。这允许:has()
创建复杂的标准来测试,使其成为一个非常强大的选择器。
为了感受它是如何:has()
工作的,让我们看一个如何应用它的例子。在下面的选择器中,我们测试一个<article>
元素是否有一个<img>
子元素:
article:has(img) {}
此选择器的可能结果如下图所示。显示了三个文章元素,其中两个包含图像,并且都具有浅绿色背景和与没有图像的元素不同的填充。
只要<img>
元素存在于该<article>
元素的任何位置,上面的选择器就会应用------无论是作为直接子元素还是作为其他嵌套元素的后代。
如果我们想确保规则仅适用于元素<img>
的直接(非嵌套)子元素<article>
,我们还可以包含子组合器:
article:has(> img) {}
此更改的结果如下图所示。显示了相同的三张卡片,但这次只有图像是 的直接子代的那一张<article>
具有浅绿色背景和填充。
在这两个选择器中,我们定义的样式都应用于目标元素,即<article>
. 这就是为什么人们经常称其为:has()
"父级"选择器:如果某些元素以某种方式存在,则它们的"父级"会收到指定的样式。
注意::has()
伪类本身不会为选择器添加任何特异性权重。:is()
和一样:not()
, 的特异性:has()
等于选择器列表中特异性最高的选择器。例如,:has(#id, p, .class)
将具有赋予id
. 要复习特异性,请查看 CSS Master, 3rd Edition 中关于特异性的部分。
如果目标元素后跟特定的兄弟元素,我们还可以使用相邻兄弟组合器 ( +
) 选择目标元素。在下面的例子中,我们<h1>
只选择一个紧跟 an 的元素<h2>
:
h1:has(+ h2) {}
在下图中,<article>
显示了两个元素。在第一个中,因为<h1>
后面跟着一个<h2>
,所以<h1>
应用了浅绿色背景。
使用通用兄弟组合器 ( ~
),我们可以检查特定元素是否是目标后面任何位置的兄弟。在这里,我们正在检查某处是否有一个<p>
元素作为 的兄弟元素<ul>
:
ul:has(~ p) {}
下图显示了两个<article>
元素,每个元素都包含一个无序列表。第二篇文章的列表后面是一段,所以它应用了浅绿色背景。
到目前为止,我们使用的选择器为附加到 的目标元素设置了样式:has()
,例如<ul>
in ul:has(~ p)
。与常规选择器一样,我们的:has()
选择器可以扩展得更复杂,例如为不直接附加到选择:has()
器的元素设置样式条件。
在下面的选择器中,样式适用于作为 an本身具有 an作为相邻兄弟姐妹<p>
的兄弟姐妹的任何元素:<h2>``<h3>
h2:has(+ h3) ~ p
在下图中,<article>
显示了两个元素。在第二个中,段落的样式为淡绿色背景和增加的左边距,因为这些段落是 an 的兄弟姐妹,<h2>
后面跟着<h3>``。
:has()
注意:如果我们对可用的 CSS 选择器有很好的理解,我们使用起来会更成功。MDN 提供了选择器的简明概述,我已经编写了一个由两部分组成的关于选择器的系列文章,其中包含更多实际示例。
请记住,:has()
可以接受一个选择器列表,我们可以将其视为OR
条件。让我们选择一个段落,如果它包含<a>
or <strong>
or <em>
:
p:has(a, strong, em) {}
在下图中,有两个段落。因为第二段包含一个<strong>
元素,所以它具有浅绿色背景。
我们也可以链式:has()
选择器来创造AND
条件。在下面的复合选择器中,我们正在测试 an<img>
是 的第一个子节点<article>
,并且 the<article>
包含 an<h1>
后跟 an <h2>
:
article:has(> img:first-child):has(h1 + h2) {}
下图显示了三个<article>
元素。第二篇文章有浅绿色背景(以及其他样式),因为它包含作为第一个子项的图像和<h1>
后跟一个<h2>``。
最后可以预览下DEMO:
<!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>CSS has 知识 | Web前端之家www.jiangweishan.com</title>
<style>
#example-1 article:has(img) {
background-color: palegreen;
padding: 0 0 2rem;
}
#example-1 article:has(img) img {
border-radius: 0.5rem 0.5rem 0 0;
}
#example-1 article:has(img) > *:not(img) {
padding-inline: 1.5rem;
}
#example-2 article:has(> img) {
background-color: palegreen;
padding: 0 0 2rem;
}
#example-2 article:has(> img) img {
border-radius: 0.5rem 0.5rem 0 0;
}
#example-2 article:has(> img) > *:not(img) {
padding-inline: 1.5rem;
}
#example-3 h1:has(+ h2) {
font-size: 3rem;
background-color: palegreen;
}
#example-3 h1:has(+ h2) + h2 {
-webkit-margin-before: 0.15em;
margin-block-start: 0.15em;
color: #797979;
font-weight: 500;
font-style: italic;
}
#example-4 ul:has(~ p) {
background-color: palegreen;
-webkit-margin-after: 2rem;
margin-block-end: 2rem;
}
#example-5 h2:has(+ h3) ~ p {
background-color: palegreen;
-webkit-margin-start: 2em;
margin-inline-start: 2em;
}
#example-6 p:has(a, strong, em) {
background-color: palegreen;
}
#example-7 article:has(> img:first-child):has(h1 + h2) {
background-color: palegreen;
padding: 0 0 2rem;
}
#example-7 article:has(> img:first-child):has(h1 + h2) img {
border-radius: 0.5rem 0.5rem 0 0;
}
#example-7 article:has(> img:first-child):has(h1 + h2) > *:not(img) {
padding-inline: 1.5rem;
}
#example-7 article:has(> img:first-child):has(h1 + h2) :is(h1, h2) {
font-weight: 500;
}
#example-7 article:has(> img:first-child):has(h1 + h2) h1 {
font-family: Georgia, serif;
font-size: 1.75rem;
font-style: italic;
}
#example-7 article:has(> img:first-child):has(h1 + h2) h2 {
-webkit-margin-before: 0.15em;
margin-block-start: 0.15em;
font-size: 1.25rem;
}
:root {
--body-bg: whitesmoke;
}
body {
font-size: 0.9rem;
}
[id] {
display: grid;
place-content: center;
gap: 4vmax;
min-height: 100vh;
padding: 5vmax;
}
[id]:not(:first-child) {
border-top: 1px dashed #797979;
}
[id] *:not([id] > h2, code, .columns) {
outline: 1px dashed #797979;
}
[id] > h2 {
text-align: center;
}
[data-tag] {
position: relative;
}
[data-tag]::before {
content: attr(data-tag);
position: absolute;
font-family: system-ui;
font-style: normal;
background-color: mediumvioletred;
letter-spacing: 0.03em;
padding: 0.25em;
font-size: 1.05rem;
font-weight: 500;
color: #fff;
top: 0;
left: 0;
transform: translate(-1ch, -33%);
border-radius: 0.25rem;
}
h1 {
font-size: 2rem;
line-height: 1.1;
}
code {
color: mediumvioletred;
letter-spacing: -0.03em;
}
article {
background-color: #fff;
border-radius: 0.5rem;
padding: 2rem;
}
article > img:first-child {
width: 100%;
-o-object-fit: cover;
object-fit: cover;
}
article > * + *,
article ul li + li {
-webkit-margin-before: 1em;
margin-block-start: 1em;
}
img {
max-width: 100%;
display: block;
}
.columns {
width: min(80ch, 100vw - 2rem);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(22ch, 1fr));
gap: 2vmax;
align-items: start;
}
</style>
</head>
<body>
<div id="example-1">
<h2><code>article:has(img)</code></h2>
<div class="columns">
<article data-tag="article">
<h3>Lorem, ipsum dolor.</h3>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
<article data-tag="article">
<img src='https://images.unsplash.com/photo-1554692901-e16f2046918a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzQwNzc0OTg&ixlib=rb-4.0.3&q=80&w=400' alt=''>
<h3>Lorem, ipsum dolor.</h3>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
<article data-tag="article">
<h3>Lorem, ipsum dolor.</h3>
<p><img src='https://images.unsplash.com/photo-1638445533129-65aaf55fb94c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzQwNzc5MjE&ixlib=rb-4.0.3&q=80&w=20' alt=''> Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
</div>
</div>
<div id="example-2">
<h2><code>article:has(> img)</code></h2>
<div class="columns">
<article data-tag="article">
<h3>Lorem, ipsum dolor.</h3>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
<article data-tag="article">
<img src='https://images.unsplash.com/photo-1554692901-e16f2046918a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzQwNzc0OTg&ixlib=rb-4.0.3&q=80&w=400' alt=''>
<h3>Lorem, ipsum dolor.</h3>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
<article data-tag="article">
<h3>Lorem, ipsum dolor.</h3>
<p><img src='https://images.unsplash.com/photo-1638445533129-65aaf55fb94c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzQwNzc5MjE&ixlib=rb-4.0.3&q=80&w=20' alt=''> Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
</div>
</div>
<div id="example-3">
<h2><code>h1:has(+ h2)</code></h2>
<article>
<h1 data-tag="h1">Lorem, ipsum dolor.</h1>
<h2>Sit amet consectetur adipisicing elit.</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati odit reprehenderit culpa.</p>
</article>
<article>
<h1 data-tag="h1">Lorem, ipsum dolor.</h1>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati odit reprehenderit culpa.</p>
</article>
</div>
<div id="example-4">
<h2><code>ul:has(~ p)</code></h2>
<div class="columns">
<article>
<ul data-tag="ul">
<li>Lorem, ipsum dolor.</li>
<li>Fugiat, officiis sint!</li>
<li>Sit, facere ratione!</li>
</ul>
</article>
<article>
<ul data-tag="ul">
<li>Lorem, ipsum dolor.</li>
<li>Labore, a blanditiis!</li>
<li>Tempora, amet consectetur.</li>
</ul>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit.</p>
</article>
</div>
</div>
<div id="example-5">
<h2><code>h2:has(+ h3) ~ p</code></h2>
<div class="columns">
<article>
<h2 data-tag="h2">Lorem, ipsum dolor.</h2>
<p data-tag="p">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima placeat quo omnis.</p>
<p data-tag="p">Expedita est consectetur pariatur in, sint maiores molestiae temporibus vitae deleniti recusandae.</p>
</article>
<article>
<h2 data-tag="h2">Sit amet consectetur</h2>
<h3 data-tag="h3">Porro delectus maxime ea</h3>
<p data-tag="p">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quod rerum quo nam.</p>
<p data-tag="p">Corrupti incidunt similique unde iste alias nostrum sit quae natus pariatur impedit?</p>
</article>
</div>
</div>
<div id="example-6">
<h2><code>p:has(a, strong, em)</code></h2>
<div class="columns">
<article>
<p data-tag="p">Lorem ipsum dolor sit amet consectetur adipisicing elit. Neque non corporis nesciunt mollitia natus. Harum.</p>
</article>
<article>
<p data-tag="p">Eaque voluptatum <strong>soluta sit ipsam</strong> nihil vel optio ratione numquam magnam. Beatae amet velit odio?</p>
</article>
</div>
</div>
<div id="example-7">
<h2><code>article:has(> img:first-child):has(h1 + h2)</code></h2>
<div class="columns">
<article data-tag="article">
<h1 data-tag="h1">Lorem, ipsum dolor.</h1>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
<article data-tag="article">
<img src='https://images.unsplash.com/photo-1554692901-e16f2046918a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzQwNzc0OTg&ixlib=rb-4.0.3&q=80&w=400' alt=''>
<h1 data-tag="h1">Lorem, ipsum dolor.</h1>
<h2 data-tag="h2">Consectetur adipisicing elit</h2>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
<article data-tag="article">
<img src='https://images.unsplash.com/photo-1526137966266-60618b40bcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzQwODM1Nzc&ixlib=rb-4.0.3&q=80&w=400' alt=''>
<h1 data-tag="h1">Lorem, ipsum dolor.</h1>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
</article>
</div>
</div>
</body>
</html>