现代 CSS 选择器的威力::has, :is 与 :where
多年来,CSS 开发者一直梦想着有一个“父级选择器”——一种根据子元素来设置父元素样式的方法。我们也曾深陷于冗长、重复的选择器列表中,这让我们的 CSS 文件变得臃肿。
现代 CSS 终于实现了这些愿望。随着 :has()、:is() 和 :where() 的到来,我们编写选择器的方式发生了根本性的变化。
1. :has():改变游戏规则的“父级选择器”
:has() 伪类可以说是近十年来 CSS 最强大的补充。它允许你根据元素是否包含特定的子元素,或者是否紧跟特定的兄弟元素来选择该元素。
“父级”应用场景
/* 仅当卡片包含图像时才设置卡片样式 */
.card:has(img) {
display: flex;
flex-direction: column;
}
/* 仅当卡片包含“精选”标签时才设置样式 */
.card:has(.featured-badge) {
border: 2px solid gold;
}
“条件”应用场景
你甚至可以根据输入框的状态来设置标签(label)的样式:
/* 如果内部的复选框被勾选,则设置标签样式 */
.form-group:has(input:checked) label {
color: green;
font-weight: bold;
}
2. :is():简化复杂的选择器
你是否写过这样的代码?
header h1, header h2, header h3, footer h1, footer h2, footer h3 {
color: blue;
}
:is() 伪类允许你对选择器进行分组并减少重复:
:is(header, footer) :is(h1, h2, h3) {
color: blue;
}
核心特性:宽容性
与传统的选择器列表不同,:is() 是宽容的。如果列表中的一个选择器无效,浏览器会忽略该无效选择器,但仍会对有效的选择器应用样式。
3. :where():零权重的力量
:where() 选择器的工作方式与 :is() 完全相同,但有一个至关重要的区别:它的权重(优先级)始终为零。
为什么权重很重要
在 CSS 中,权重最高的选择器获胜。这通常会导致“权重战争”,开发者不得不使用 !important 或长长的选择器链来覆盖样式。
/* 这对权重没有影响 */
:where(.content) p {
color: gray;
}
/* 一个简单的类选择器现在就可以轻松覆盖它 */
.special-p {
color: red; /* 获胜,因为 :where() 没有增加任何“重量” */
}
:where() 非常适合 CSS 重置(Resets) 和库作者,他们希望提供易于被用户覆盖的默认样式。
4. 增强型 :nth-child 与 of S
你可能知道 :nth-child(even),但你知道现在可以使用 of 关键字来过滤选择吗?
/* 在所有带有 .visible 类的元素中,选择第 2 个项目 */
li:nth-child(2 of .visible) {
background: yellow;
}
这对于一些动态列表非常有用,特别是当某些项目通过 display: none 隐藏时。
5. 权重计算器:理解其中的数学逻辑
CSS 权重使用三列进行计算:(A, B, C)。
- A:ID 选择器
- B:类选择器、属性选择器和伪类
- C:元素选择器和伪元素
新选择器如何影响计算:
:is()和:has():它们的权重等于其参数列表中权重最高的选择器。:where():权重始终为 (0, 0, 0)。
常见问题 FAQ
问::has() 在所有浏览器中都支持吗?
答: 是的!截至 2023 年底,:has() 已在 Chrome、Safari、Firefox 和 Edge 的最新版本中得到支持。在现代 Web 项目中可以放心使用。
问:我应该什么时候使用 :is(),什么时候使用 :where()?
答: 当你希望分组的选择器保持其正常权重时,使用 :is()。当你希望样式非常容易被覆盖时(常见于基础样式或重置样式),使用 :where()。
问::has() 会影响性能吗?
答: 浏览器对 :has() 进行了显著优化。虽然在单个页面上使用数百次可能会产生微小的影响,但对于大多数 UI 模式来说,它的速度非常快且高效。
编写更简洁、更具声明性的 CSS
通过掌握这些选择器,你可以显著减少 HTML 中的“实用类(utility classes)”数量,并将逻辑保留在它所属的地方:CSS 样式表中。
想看看你的选择器权重如何?试试我们的 CSS 选择器权重计算器(即将推出),掌握 CSS 的数学逻辑。