早在去年 12 月,我们就写了一篇文章,详细介绍了 CSS 嵌套的三种不同选择。在其中,我们解释了选项 3、选项 4 和选项 5 之间的区别,并通过一系列示例演示了每个选项的工作原理。然后我们问了一个简单的问题:“哪个选项最适合 CSS 的未来?”
Web 开发人员非常清楚地回应了民意调查。选项 3 以压倒性优势获胜。
所以现在,Safari 和 Chrome 都实现了选项 3。两周前,也就是 1 月 25 日,CSS Nesting在Safari Technology Preview 162中默认启用。如果您有 Mac,只需下载并打开 Safari Technology Preview,编写一些嵌套的 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
as ,它也会以同样的方式失败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 中——任意多的层次。您可以根据需要将嵌套与容器查询、特征查询、媒体查询和/或级联层混合使用。任何东西都可以进入任何东西。
立即尝试 CSS 嵌套,看看您的想法。在 Safari Technology Preview 和 Chrome Dev 中测试你的代码(在翻转“Experimental Web Platform features”标志之后)以确保它产生相同的结果。这是发现错误的最佳时机——在任何浏览器推出此新功能之前。您可以在bugs.webkit.org或bugs.chromium.org报告问题。另外,请留意Safari Technology Preview 下几个版本的发行说明。每个都可能会改进我们的 CSS 嵌套实现,包括增加对 CSSOM 的支持或其他更新以匹配 CSS 工作组所做的任何潜在规范更改。
近五年来,多家公司的许多人一直致力于将嵌套引入 CSS。在关于许多不同解决方案的优缺点的长时间对话中,对语法进行了激烈的辩论。我们希望您发现结果非常有帮助。