早在去年 12 月,我们就写了一篇文章,详细介绍了 CSS 嵌套的三种不同选择。在其中,我们解释了选项 3、选项 4 和选项 5 之间的区别,并通过一系列示例演示了每个选项的工作原理。然后我们问了一个简单的问题:“哪个选项最适合 CSS 的未来?”

Web 开发人员非常清楚地回应了民意调查。选项 3 以压倒性优势获胜。

所以现在,Safari 和 Chrome 都实现了选项 3。两周前,也就是 1 月 25 日,CSS NestingSafari 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以字母而不是符号开头。怎么会失败呢?如果你拼错了articleas ,它也会以同样的方式失败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.orgbugs.chromium.org报告问题。另外,请留意Safari Technology Preview 下几个版本的发行说明。每个都可能会改进我们的 CSS 嵌套实现,包括增加对 CSSOM 的支持或其他更新以匹配 CSS 工作组所做的任何潜在规范更改。

近五年来,多家公司的许多人一直致力于将嵌套引入 CSS。在关于许多不同解决方案的优缺点的长时间对话中,对语法进行了激烈的辩论。我们希望您发现结果非常有帮助。

立即尝试 CSS 嵌套
标签: