Native CSS将支持CSS嵌套。这是一个非常好的功能,原因有很多,其中最重要的一点是更容易写出干净易懂的CSS代码。
这是怎么一回事呢?让我们讨论一下什么是嵌套,以及它在预处理器中是如何使用的。然后,我们将讨论它的一些优点,以及它将如何在CSS中被原生使用。
什么是CSS嵌套?
你可能对这样写CSS很熟悉。
.header {
background-color: blue;
}
.header p {
font-size: 16px;
}
.header p span:hover{
color: green
}
考虑一下用CSS嵌套的另一种方式来写这些相同的样式。
.header {
background-color: blue;
p {
font-size: 16px;
span {
&:hover {
color: green
}
}
}
}
这种语法在SCSS和Less等CSS预处理程序中已经成为可能。从这两段代码中你可以看到,嵌套是将一个选择器包围在另一个选择器中。嵌套可以帮助你将相关的样式分组,并以嵌套的层次结构编写CSS。
如果你认为这有什么不同,请考虑一下,你一直在用HTML做这件事。所以,与其重复写同一个选择器来为特定的子元素或伪选择器设置样式,不如直接将它们嵌套在一个选择器下。
嵌套的优点
从上面的段落中,你已经可以看到使用嵌套的一些优势。让我们再考虑两个。
- 编写更加模块化和可维护的样式表。与其把同一个选择器放在一个样式表的多个地方,你可以把所有与该选择器相关的样式放在一个地方。这将使开发时间和调试时间大大加快
- 它允许你嵌套媒体查询。有了嵌套,就不需要为一个选择器单独制定媒体查询规则。你可以在你定义选择器的地方添加这个规则。
现在的问题是,"我们如何在本地CSS中使用CSS嵌套?"
如何在CSS中嵌套选择器
在CSS中嵌套的方法与我们在上面的例子中看到的基本相同。但是,你需要在每个嵌套的选择器中用安培尔& ,或者用@nest 规则开始。让我们用本地CSS嵌套重写上面的代码。
.header {
background-color: blue;
& p {
font-size: 16px;
& span {
&:hover {
color: green
}
}
}
}
注意到每个选择器的开头有& ?这在CSS中是需要的,这样嵌套才会有效。另外,注意到&:hover 保持不变。在这种情况下,没有必要增加一个额外的& 。
让我们再举个例子。如果你想用原生的CSS嵌套来写像下面这样的复合选择器。
h1.header {
font-weight: 700
}
你这样做。
h1 {
&.header {
font-weight: 700
}
}
注意,如果你想在同一个元素上为一个类添加一个选择器,那么在& 和选择器之间没有空格。
这是一个嵌套媒体查询的例子。
.header {
font-size: 40px
@media (max-width: 760px ) {
& {
font-size: 24px;
}
}
}
我们可以看到,这对于将类似的样式组合在一起是多么有帮助。
@nest 规则
虽然用& 直接嵌套看起来很完美,但有一些有效的嵌套选择器是它无法处理的。让我们考虑一个例子。
.header {
background-color: white;
.dark & {
background-color: blue;
}
}
上面的嵌套对于嵌套选择器是有效的。但是CSS中的直接嵌套却无法处理它。这就是@nest 规则的作用。
@nest 规则允许嵌套在CSS中更加灵活。因此,只要嵌套选择器中有一个嵌套选择器(&),而不是只在嵌套选择器的开头设置嵌套选择器,@nest 规则允许嵌套不受限制。
上面的例子可以用@nest 规则来解决。
.header {
background-color: white;
@nest .dark & {
background-color: blue;
}
}
这就相当于。
.header {
background-color: white;
}
.dark .header {
background-color: blue;
}
另一个例子。
.header {
background-color: white;
@nest :not(&) {
background-color: blue;
}
}
这相当于。
.header {
background-color: white;
}
:not(.header) {
background-color: blue;
}
请注意,要使@nest 规则有效,直接嵌套选择器(&)必须在嵌套选择器中存在,否则将无效。所以下面的例子是无效的,因为没有嵌套选择器存在。
.header {
background-color: white;
@nest .dark {
background-color: blue;
}
}
注意,现在并不是所有的浏览器都支持CSS,但是你可以使用PostCSS将你的嵌套CSS转换为浏览器能够理解的有效CSS。
CSS嵌套和特异性
在CSS中,特异性是一组决定哪些样式适用于某个元素的规则。如果有两个或更多的选择器适用于同一个元素,则应用特异性最高的那个。例如,考虑下面的例子。
<html>
<h1 class="header" id="header" />
</html>
<style>
#header {
color: red;
}
.header {
color: blue;
}
h1 {
color: green;
}
</style>
CSS层叠,所以理想情况下,应该应用样式表中最后一个选择器(h1)。
然而,H1 元素的颜色将是red ,因为id 选择器(#header)的特异性更高。关于特异性的更详细的解释,你可以阅读这篇关于特异性的详细文章。
这与CSS嵌套有什么关系呢?让我们来看看,当我们使用嵌套时,在浏览器中会发生什么。考虑一下这个例子。
#header, p {
& span {
color: red;
}
}
这就相当于。
:is(#header, p) span (color: red)
:is 选择器在所有选择器中使用了最高的特异性,所以将很难覆盖这些样式。如果你有一个p 元素,你想改变span 的颜色,比如说,像下面这样。
<p class="paragraph">
<span>hey there <span>
</p>
<style>
#header, p {
& span {
color: red;
}
}
.paragraph {
& span {
color: green;
}
}
</style>
颜色red 仍然会被应用,因为#header 的特异性高于类.paragraph 。
这一点很重要,可以避免诉诸非常复杂的选择器或使用!important 来覆盖样式。接下来,让我们考虑一些使用嵌套时要遵循的一般准则。
使用嵌套的常见指南
避免过度嵌套
由于嵌套使得嵌套样式变得容易,你可能会被诱惑去过度嵌套选择器。考虑一下下面的例子。
main {
& section {
background-color: red;
& ul {
background-color: green;
& .list {
font-size: 16px;
& .link {
color: pink;
& :hover {
color: blue
}
}
}
}
}
}
这相当于
main section {
background-color: red;
}
main section ul {
background-color: green;
}
main section ul .list{
font-size: 16px;
}
main section ul .list .link{
color: pink;
}
main section ul .list .link:hover{
color: blue;
}
最后一个选择器有六层嵌套。如果你想覆盖这些样式,这可能会导致很多具体问题。作为一般指导,保持嵌套只有三层深度。你可以使用stylelint来控制这个问题。尽可能地使用具有描述性名称的类。
嵌套选择器后的样式会被忽略
在使用嵌套的时候,这一点要牢记。考虑一下这个例子。
main {
& section {
background-color: red;
}
color: green;
}
color: green 将被忽略,因为它在嵌套的选择器之后。在CSS嵌套中,任何样式都应该在嵌套选择器之前应用。这是CSS嵌套与其他预处理程序嵌套的一个区别。
总结
嵌套是一个令人兴奋的功能,很快就会被添加到本地CSS中。在这篇文章中,我们已经讨论了以下几点。
- 嵌套将有助于保持样式表的模块化和更易于维护。这是因为通过嵌套,所有与选择器、子/父选择器相关的样式,甚至媒体查询都可以嵌套在同一个地方。
- 如何以及何时可以使用直接嵌套和
@nest规则 - 为什么在使用嵌套时要记住特殊性,避免过度嵌套?
关于CSS嵌套的进一步研究,你可以参考W3C的CSS嵌套模块草案。
The postNative CSS nesting:你需要知道的东西出现在LogRocket博客上。