一、概述
根据 CSS 规范,:has 选择器可以检查父元素是否包含至少一个元素,或者一个条件,例如输入是否获取到焦点。
:has 选择器不仅可以检查父元素是否包含特定的子元素,还可以检查一个元素后面是否跟有另一个元素:
1 2 3 4 5 6 7
| // 这将检查 <h2> 元素是否直接跟在 <p> 元素之后 .card h2:has(+ p) { }
// 检查输入是否获取到了焦点 form:has(input:focused) { background-color: lightgrey; }
|
二、使用场景
1、当处理章节标题时有两种情况,一种是只包含标题,另一种包含标题和链接。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <section> <div class="section-header"> <h2>Latest articles</h2> <a href="/articles/>See all</a>
</div> </section>
.section-header { display: flex; justify-content: space-between; } // 是否有链接来定义不同的样式 .section-header:has(> a) { // :has(> a) 表示只选择直接子元素 align-items: center; border-bottom: 1px solid; padding-bottom: 0.5rem; }
|
2、有两种类型的卡片操作:一种只有一个操作(链接),另一种具有多个操作(保存、分享等)。

当图片具有多个操作时需要给这些操作添加display: flex,可以这样来实现:
1 2 3 4
| .card-actions:has(.start, .end) { display: flex; justify-content: space-between; }
|
3、 根据是否有图片来重置卡片组件的border-radius。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| .card:not(:has(img)) .card-content { border-top-left-radius: 12px; border-top-right-radius: 12px; }
.card img { border-top-left-radius: 12px; border-top-right-radius: 12px; }
.card-content { border-bottom-left-radius: 12px; border-bottom-right-radius: 12px; }
|
4、 有一个具有多个选项的组件,当它们没有被选中时,不显示重置按钮。当选中其中一个选项时,显示重置按钮。

1 2 3 4 5 6 7 8
| .btn-reset { display: none; }
.multiselect:has(input:checked) .btn-reset { display: block; }
|
5、有时可能需要根据之前的选择来显示特定的表单字段。在下面的例子中,当下拉框选中“other”字段时,就展示 other reason 输入框:

1 2 3 4 5 6 7 8
| .other-field { display: block; }
form:has(option[value="other"]:checked) .other-field { display: block; }
|
6、 根据是否展示子菜单来显示或隐藏右侧的箭头

1 2 3
| li:has(ul) > a:after { content: ""; }
|
7、在某些仪表板中,可能需要用户必须注意重要警报。在这种情况下,拥有页内警报可能还不够。例如,在这种情况下,可能会为标题元素添加红色边框和暗红色背景色。这样会增加用户快速注意到警报的可能性。

1 2 3 4
| .main:has(.alert) .header { border-top: 2px solid red; background-color: #fff4f4; }
|
8、 可以使用 CSS :has 来更改网站的配色方案。例如,如果有多个使用 CSS 变量构建的主题,可以通过<select>
菜单来进行切换。
1 2 3 4
| html:has(option[value="blueish"]:checked) { --color-1: #9e7ec8; --color-2: #f1dceb; }
|
9、有一个默认的按钮样式。当按钮中包含图标时,使用 flexbox 来居中对齐按钮的内容:

1 2 3 4 5
| .button:has(.c-icon) { display: inline-flex; justify-content: center; align-items: center; }
|
10、 有一组操作按钮,如果超过 2 个按钮,则最后一个按钮显示在右侧

1 2 3 4 5 6 7 8 9
| .btn-group { display: flex; align-items: center; gap: 0.5rem; } .btn-group:has(.button:nth-last-child(n + 3)) .button:last-child { margin-left: auto; }
|
11、 使用 CSS grid 布局中,可以使用 minmax() 功能创建真正响应式和自动调整大小的网格项。然而,这可能还不够,我们还想根据项目数量来改变网格。

1 2 3 4 5 6
| .wrapper { --item-size: 200px; display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--item-size), 1fr)); gap: 1rem; }
|
当有 5 个项目时,最后一个将换行:

可以通过检查.wrapper中是否有 5 个或更多项目来解决这个问题。同样,这是使用到了数量查询的概念。
1 2 3
| .wrapper:has(.item:nth-last-child(n + 5)) { --item-size: 120px; }
|
实现效果如下:

12、可以使用 CSS 中的@supports规则来判断浏览器是否支持该选择器:
1
| @supports selector(:has(*)) {}
|