本地CSS嵌套。你需要知道什么

220 阅读6分钟

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做这件事。所以,与其重复写同一个选择器来为特定的子元素或伪选择器设置样式,不如直接将它们嵌套在一个选择器下。

嵌套的优点

从上面的段落中,你已经可以看到使用嵌套的一些优势。让我们再考虑两个。

  1. 编写更加模块化和可维护的样式表。与其把同一个选择器放在一个样式表的多个地方,你可以把所有与该选择器相关的样式放在一个地方。这将使开发时间和调试时间大大加快
  2. 它允许你嵌套媒体查询。有了嵌套,就不需要为一个选择器单独制定媒体查询规则。你可以在你定义选择器的地方添加这个规则。

现在的问题是,"我们如何在本地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博客上。