立即试用 CSS 嵌套
早在去年 12 月,我们发表了一篇文章,详细介绍了 CSS 嵌套的三种不同选项。在文章中,我们解释了选项 3、选项 4 和选项 5 之间的区别,并通过一系列示例演示了它们各自的工作方式。然后我们提出了一个简单的问题:“哪种选项最适合 CSS 的未来?”
Web 开发者对投票做出了明确回应。选项 3 以压倒性优势获胜。
因此,现在 Safari 和 Chrome 都已实现了选项 3。两周前,即 1 月 25 日,CSS 嵌套已默认在 Safari 技术预览版 162 中发布。如果您有 Mac,只需下载并打开 Safari 技术预览版,编写一些嵌套 CSS,即可体验其工作原理!
CSS 嵌套的工作原理
想象一下,您有一些 CSS 希望以更紧凑的方式编写。
.foo {
color: green;
}
.foo .bar {
font-size: 1.4rem;
}
借助 CSS 嵌套,您可以这样编写代码:
.foo {
color: green;
.bar {
font-size: 1.4rem;
}
}
如果您一直在 Sass 中嵌套样式,您会发现这非常熟悉。
然而,与 Sass 不同的是,这种嵌套并非总是有效。由于浏览器解析引擎的限制,您必须确保嵌套选择器(上述示例中的 .bar
)始终以符号开头。
如果它是类、ID、伪类、伪元素、属性选择器,或者任何以符号开头的选择器 — 您都成功了。例如,所有这些都将正常工作。以下所有嵌套选择器都以符号开头 — .
#
:
[
*
+
>
~
— 而不是字母。
main {
.bar { ... }
#baz { ...}
:has(p) { ... }
::backdrop { ... }
[lang|="zh"] { ... }
* { ... }
+ article { ... }
> p { ... }
~ main { ... }
}
然而,有一种选择器是以字母开头的 — 嵌套元素选择器。这个例子将不起作用:
main {
article { ... }
}
那段代码将失败,因为 article
以字母开头,而不是符号。它将如何失败?就像您将 article
拼写为 atirlce
时那样。依赖该特定选择器的嵌套 CSS 将被简单地忽略。
您有几个选项来解决这个限制。让我们首先看看您最常使用的解决方案。您可以简单地在元素选择器前面放置一个 &
,像这样:
main {
& article { ... }
}
&
向浏览器发出信号:“我希望这个嵌套外部的选择器放置在这里”。通过在任何元素选择器前面使用 &
,您就可以成功地使嵌套选择器以符号而不是字母开头。因此,它会起作用。
aside {
& p { ... }
}
是以下代码的嵌套等价物:
aside p { ... }
&
对于其他用例也非常方便。
想象您有以下未嵌套的代码:
ul {
padding-left: 1em;
}
.component ul {
padding-left: 0;
}
您会注意到预期的选择器是 .component ul
— 其中 ul
在第二位。
要编写产生这种结果的嵌套规则,您可以这样写:
ul {
padding-left: 1em;
.component & {
padding-left: 0;
}
}
同样,&
提供了告诉您“我希望嵌套选择器放置在这里”的方式。
当您不希望选择器之间有空格时,它也很方便。例如:
a {
color: blue;
&:hover {
color: lightblue;
}
}
这样的代码产生与 a:hover {
相同的结果。如果没有 &
,您会得到 a :hover {
— 注意 a
和 :hover
之间的空格 — 这将导致您的悬停链接样式失效。
但是,如果您有以下未嵌套的代码呢?
ul {
padding-left: 1em;
}
article ul {
padding-left: 0;
}
您不应该这样编写嵌套版本:
ul {
padding-left: 1em;
& article & {
padding-left: 0;
}
}
为什么不呢?因为那实际上会与以下未嵌套的规则表现相同:
ul {
padding-left: 1em;
}
ul article ul {
padding-left: 0;
}
ul article ul
中有两个无序列表?不,那不是我们想要的。
那么,我们该怎么做呢?既然我们需要让 article &
以符号开头?
我们可以这样编写代码:
ul {
padding-left: 1em;
:is(article) & {
padding-left: 0;
}
}
任何选择器都可以被 :is()
伪类包裹,并保持相同的特异性和含义(当它是括号内唯一的选择器时)。将元素选择器放在 :is()
内部,您将获得一个以符号开头的选择器,这符合 CSS 嵌套的要求。
总而言之,CSS 嵌套将像 Sass 一样工作,但有一个新规则:您必须确保嵌套选择器始终以符号开头。
目前正在调查是否可以在不减慢解析引擎速度的情况下放宽此限制。该限制很可能会被移除 — 无论是很快还是几年后。每个人都同意,如果没有这种限制,嵌套会好得多。但我们也一致认为,网页必须立即显示在浏览器窗口中。在渲染开始前增加哪怕是极小的暂停都不是一个选项。
什么是一个选项?您可以随意构建您的嵌套代码。您可以嵌套多层 — 在已嵌套的 CSS 中嵌套 CSS — 达到您想要的任意深度。您可以随意将嵌套与容器查询(Container Queries)、特性查询(Feature Queries)、媒体查询(Media Queries)和/或层叠层(Cascade Layers)混合使用。任何内容都可以嵌套在任何内容中。
今天就尝试 CSS 嵌套,看看您的想法。在 Safari 技术预览版和 Chrome 开发者版(启用“实验性 Web 平台功能”标志后)中测试您的代码,以确保其产生相同的结果。这是发现 bug 的最佳时机 — 在此新功能发布到任何浏览器之前。您可以在 bugs.webkit.org 或 bugs.chromium.org 报告问题。此外,请关注 Safari 技术预览版接下来几个版本的发布说明。每个版本都可能为我们的 CSS 嵌套实现添加改进,包括支持 CSSOM 或其他更新的努力,以匹配 CSS 工作组可能进行的任何规范更改。
来自多家公司的许多人近五年来一直致力于将嵌套引入 CSS。其语法经过了激烈辩论,就许多不同解决方案的优缺点进行了长时间的讨论。我们希望您会发现结果非常有帮助。