嵌套是应用Sass等CSS预处理器的外围起因之一。当初,该性能曾经以相似的语法呈现在规范浏览器CSS中。你是否在构建零碎时放弃对预处理器的依赖?

CSS嵌套能够节俭输出工夫,并使语法更易于浏览和保护。迄今为止,你必须像这样键入残缺的选择器门路:

.parent1 .child1,.parent2 .child1 {  color: red;}.parent1 .child2,.parent2 .child2 {  color: green;}.parent1 .child2:hover,.parent2 .child2:hover {  color: blue;}

当初,你能够将子选择器嵌套在父选择器中,比方:

.parent1, .parent2 {  .child1 {    color: red;  }  .child2 {    color: green;    &:hover {      color: blue;    }  }}

你能够嵌套任意层级的选择器,但要留神不要超过两到三级。嵌套层级没有技术层面的限度,然而会让代码更难浏览,并且让最终CSS变得很简短。

直到2023年四月,暂没有浏览器反对CSS嵌套语法。你须要应用 CSS 预处理器(如 Sass、Less 或 PostCSS)进行构建步骤,以便将嵌套代码转换为惯例的全选择器语法。嵌套性能现已在Chrome 112+和Safari 16.5+中实现,Firefox将在2023年晚些时候提供反对。

CSS原生嵌套规定

你能够将任何选择器嵌套到另一个选择器中,但必须以符号结尾,如&.(用于HTML class),#(用于HTML id),@(用于媒体查问),:::*+~>,或 [。换句话说,它不能间接援用HTML元素。上面的代码有效,<p>选择器不会被解析:

.parent1 {  /* FAILS */  p {    color: blue;  }}

修复该问题最简略的办法就是应用&,其与Sass雷同的形式援用以后选择器:

.parent1 {  /* WORKS */  & p {    color: blue;  }}

或者,能够这么解决:

  • > p - 但这将仅对 .parent1 的间接子元素进行款式调整
  • :is(p) - 然而:is()应用最优先选择器的优先级
  • :where(p) - 然而:where()的优先级为0

在这个简略的示例中,它们都能够工作,但在当前应用更简单的样式表时,你可能会遇到优先级问题。

&还容许你在父选择器上定位伪元素和伪类。例如:

p.my-element {  &::after {}  &:hover {}  &:target {}}

如果你不应用&,你的指标将是选择器的所有子元素,而不是p.my-element自身。(在Sass中也会呈现同样的状况)。

须要留神的是,你能够在选择器的任何地位应用&,比方:

.child1 {  .parent3 & {    color: red;  }}

这会转换为下列非嵌套语法:

.parent3 .child1 { color: red; }

你甚至能够在一个选择器中应用多个&符:

ul {  & li & {    color: blue;  }}

这会作用于嵌套的<ul>元素(ul li ul),如果你不想被逼疯我倡议还是不要这么应用了!

最初,你能够嵌套媒体查问。上面的代码为段落元素利用了cyan色彩,除非浏览器宽度至多为800px,否则将变为purple

p {  color: cyan;  @media (min-width: 800px) {    color: purple;  }}

CSS原生嵌套问题

原生嵌套在:is()中包裹父选择器,这可能会导致与Sass输入的差别。

思考下列的嵌套代码:

.parent1, #parent2 {  .child1 {}}

在浏览器中解析时,这实际上变成了以下内容:

:is(.parent1, #parent2) .child1 {}

.parent1中的.child1元素的优先级为101,因为:is()应用了其最优先选择器的优先级--在本例中,是#parent2 ID。

Sass编译的代码与此雷同:

.parent1 .child1,#parent2 .child1 {}

在本例中,.parent1 中的 .child1 元素的特异性为 002,因为它匹配两个类(#parent2 被疏忽)。它的选择器比原生选项的优先级低,在级联中被笼罩的可能性更大。

你可能还会遇到一个更奥妙的问题。思考下列代码:

.parent .child {  .grandparent & {}}

原生CSS等价于:

.grandparent :is(.parent .child) {}

这与下列排序谬误的HTML元素相匹配:

<div class="parent">  <div class="grandparent">    <div class="child">MATCH</div>  </div></div>

因为CSS解析器会执行以下操作,因而MATCH会扭转款式:

  1. 在DOM层次结构中的任意地位,找到所有类为child的元素,同时先人元素的类为parent
  2. 在找到蕴含MATCH的元素后,解析器会查看该元素是否有一个先人为grandparent的元素--同样是在DOM层次结构中的任意地位。找到后,解析器会相应地对该元素利用款式。

在Sass中不是这种状况,最终会编译成这样:

.grandparent .parent .child {}

下面的HTML没有款式化,因为元素的类没有遵循严格的grandparentparentchild程序。

最初,Sass应用字符串替换,所以像上面这样的申明是无效的,能够匹配任何具备outer-space类的元素:

.outer {  &-space { color: black; }}

而原生CSS会疏忽&-space选择器。

还须要CSS预处理器吗

在短期内,现有的CSS预处理器依然必不可少。

Sass开发团队曾经发表,他们将反对.css文件中的原生CSS嵌套,并按原样输入代码。他们将判若两人地编译嵌套的SCSS代码,以防止毁坏现有代码库,但当寰球浏览器支持率达到98%时,他们将开始输入:is()选择器。

我猜想PostCSS插件等预处理器目前会扩大嵌套代码,但当浏览器支持率越来越高时,就会移除该性能。

当然,应用预处理器还有其余很好的理由--比方将局部代码捆绑到繁多文件中,以及精简代码。但如果嵌套是你惟一须要的性能,那么你当然能够思考在小型我的项目中应用本地CSS。

总结

CSS嵌套是最有用、最实用的预处理器性能之一。浏览器供应商努力创造了一个本地CSS版本,其相似性足以让Web开发人员称心。尽管两者之间存在细微差别,而且在应用(过于)简单的选择器时可能会遇到不寻常的优先级问题,但很少有代码库须要进行彻底批改。

原生嵌套可能会让你重新考虑对CSS预处理器的需要,但它们仍能提供其余益处。Sass和相似工具依然是大多数开发人员工具包的重要组成部分。

以上就是本文的全部内容。如果对你有所帮忙,欢送点赞、珍藏、转发~