CSS:has()指南
# 写在前面
本篇文章是翻译学习原文链接 (opens new window)。查看原文可以更好的查看相应的属性效果。
# 介绍
我们一直希望在 CSS 中能够根据元素的后代来设置元素的样式。直到所有主流浏览器都支持 CSS :has() 后,这才得以实现。在本文中,我将探讨这个问题,并展示 CSS :has() 的一些有趣用例。
# 问题
假设我们有一个 figure 标签,如果它有一个 figcaption 子元素,我们想给它设置不同的样式。如何在 CSS 中实现?
<figure>
<img src="thumb.jpg" alt="" />
<figcaption>A great looking tart.</figcaption>
</figure>
2
3
4
参见以下演示。尝试切换“显示标题”。
当有标题时,我希望图形具有以下内容:
- padding 边距
- background 背景色
- shadow 阴影
CSS 中唯一可能的方法是给 figure 赋予一个类,然后从该类中选择 figcaption。
<template>
<div class="figure-wrap">
<el-checkbox v-model="showCaption">展示标题</el-checkbox>
<figure :class="[showCaption ? 'with-caption' : '']">
<img class="img" src="@/assets/images/logo.jpeg" alt="" />
<figcaption v-if="showCaption">A great looking tart.</figcaption>
</figure>
</div>
</template>
<script lang="ts" setup>
const showCaption = ref(false)
</script>
<style lang="less" scoped>
.figure-wrap {
display: flex;
flex-direction: column;
align-items: center;
background-color: #2196f317;
padding: 1rem;
border-radius: 8px;
min-height: 180px;
.img {
width: 300px;
height: 300px;
}
}
figure.with-caption {
padding: 0.5rem;
background-color: #fff;
box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 解决
使用 CSS :has() 选择器,这是可能的。我们可以执行以下操作。这就像说如果 figure 包含 figcaption,则按该方式设置样式。 当 figcaption 显示时,figure 就会设置相应样式。
figure:has(figcaption) {
padding: 0.5rem;
background-color: #fff;
box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
2
3
4
5
6
这只是简单介绍了我们可以使用 CSS :has() 解决的问题的表面。
# css 选择器回顾
在深入研究 :has() 的一些有趣的 CSS 选择器之前,让我们先快速回顾一下它们。
# 相邻兄弟选择器
要选择元素的下一个同级元素,我们可以使用相邻同级选择器 (+)。
.book {
opacity: 0.2;
}
.frame + .book {
opacity: 1;
}
2
3
4
5
6
7
# 通用兄弟选择器
要选择元素的所有下一个兄弟元素,我们可以使用通用兄弟选择器 (~)。
.book {
opacity: 0.2;
}
.frame ~ .book {
opacity: 1;
}
2
3
4
5
6
7
# 前一个兄弟选择器
使用 CSS :has(),我们可以进一步利用上述内容,选择一个元素的前一个兄弟元素。
.book {
opacity: 0.2;
}
.book:has(+ .frame) {
opacity: 1;
}
2
3
4
5
6
7
在上述内容的基础上,我们可以选择特定元素的所有前面的元素。在我们的例子中,我们想要选择 .frame 元素之前的所有 .book。
.book {
opacity: 0.2;
}
.book:has(~ .frame) {
opacity: 1;
}
2
3
4
5
6
7
# 子组合选择器
> 选择器仅在元素是直接子元素时才选择该元素。例如,使用 .section > h1 仅当 h1 是该节的直接子元素时,才会选择该元素。 例如
<div class="box">
<div class="book"></div>
<div class="book"></div>
<div class="book"></div>
</div>
2
3
4
5
.box > .book {
opacity: 1;
}
2
3
# :not 伪类
CSS 中的 :not() 选择器可用于从选择中排除元素。例如,.section:not(.featured)。下面的演示就是选择除 .blue 之外的所有元素。
<div class="book"></div>
<div class="book"></div>
<div class="book blue"></div>
<div class="book"></div>
2
3
4
.book:not(.blue) {
opacity: 1;
}
.blue {
background-color: blue;
}
2
3
4
5
6
以上就是选择器回顾的全部内容。
# CSS :has() selectors matching
学习阅读 CSS :has() 选择器很有用。在本节中,我将介绍几个示例并向您展示如何使用它们。
# 带图像的卡片
在此示例中,我们有一张卡片,其中包含一个图像作为子元素。我们可以使用 CSS :has() 进行检查。
<div class="card-img-wrap">
<el-checkbox v-model="showImg">展示图片</el-checkbox>
<div class="card">
<img v-if="showImg" src="@/assets/images/login_human.png" alt="" />
<div class="card-content">
<span>.card:has(> img)</span>
<i :class="['iconfont', showImg ? 'icon-success' : 'icon-fail']"></i>
</div>
</div>
</div>
2
3
4
5
6
7
8
9
10
.card {
text-align: center;
.card-content {
i {
color: red;
}
}
}
.card:has(img) {
.card-content {
span {
font-weight: bold;
color: #2f91f4;
}
i {
color: green;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
如果我们想要一个选择器,只有当图像是卡片的直接子元素时才匹配,该怎么办?当存在 .card-thumb 元素时,它不会匹配。
.card:has(> img) {
.card-content {
span {
font-weight: bold;
color: #2f91f4;
}
i {
color: green;
}
}
}
2
3
4
5
6
7
8
9
10
11
# 不带图像的卡片
CSS :has() 可以与 :not() 选择器结合使用。在这种情况下,卡片选择器只有在没有图像的情况下才会匹配。
.card:not(:has(img)) {
.card-content {
span {
font-weight: bold;
color: #2f91f4;
}
i {
color: green;
}
}
}
2
3
4
5
6
7
8
9
10
11
# 相邻兄弟和 :has
想要选择.frame 后面跟着.book-purple 的的 .shelf。
.shelf:has(.frame + .book-purple) {
}
2
举一反三,以下组合你都能知道什么意思吗?
.shelf:has(.box > .book) {
}
.box: has(.book: nth-last-child(n + 3)) {
}
2
3
4
5
# CSS 中的逻辑运算符 :has
使用 CSS :has(),我们可以模拟逻辑运算符,如“&&”和“||”。
- &&
.shelf:has(.book-purple):has(.book-yellow) {
outline: dashed 2px deeppink;
}
2
3
- ||
.shelf:has(.book-purple, .book-yellow) {
outline: dashed 2px deeppink;
}
2
3
# 查看 has()逻辑运算符实现的神奇功能
动态改变菜单布局,查看更多 🔗 (opens new window)
# 其他
CSS :has() 是一项强大的功能,它开启了许多以前不可能实现的可能性。它确实赋予了我们 CSS 超能力!我建议您今天就开始使用它并进行尝试。