已经很久没有关注CSS本身的发展了,看到一篇国外的文章介绍了CSS Nesting特性,感觉挺有意思的。

CSS Nesting模块定义了一种用于嵌套选择器的语法,提供了将一个样式规则嵌套在另一个样式规则内部的能力,子规则的选择器相对于父规则的选择器。

CSS Nesting与CSS预处理器(如Sass)不同,它是由浏览器解析的,而不是由CSS预处理器预先编译的。

CSS Nesting有助于提高CSS样式表的可读性、模块化和可维护性。它还可能有助于减小CSS文件的大小,从而减少用户下载的数据量。

我们都使用过Sass,Less这些CSS预处理工具,写CSS非常的舒服,用多了之后你可能已经忘记了原始的CSS如何写的,这些CSS预处理工具极大的提升了前端的开发效率和体验。

浏览器支持情况

使用Can I use网站查看哪些浏览器支持了CSS Nesting的特性

Can I use

我们可以看到Firefox是支持得相对较好的,在多个版本都添加了CSS Nesting的支持,其次是Safari的技术预览版,其他浏览器也在跟进,像Chrome、Edge、Opera都已经部分支持CSS Nesting的功能。

CSS Nesting应用

Sep 20, 2023年9月20号,Safari Technology Preview 179发布了一个对CSS Nesting的更新,添加了对新的“宽松解析行为”的支持。这意味着你不再需要担心每个嵌套选择器是否以符号开头。它意味着现在像这样的嵌套CSS将正常工作:

1
2
3
4
5
article {
  h1 {
    font-size: 1.8rem;
  }
}

上面的代码等同于

1
2
3
article h1 {
  font-size: 1.8rem;
}

而在之前的版本当中, h1 标签前面必须有一个符号出现才可以实现嵌套的特性

1
2
3
4
5
6
/* 更早的版本 */
article {
  & h1 {
    font-size: 1.8rem;
  }
}

现在已经完全不需要前置的符号了,这里的符号指的是+ > ~ 等。

官方的草案给出了CSS Nesting的语法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
main {
  div { ... }
  .bar { ... }
  #baz { ...}
  :has(p) { ... }
  ::backdrop { ... }
  [lang|="zh"] { ... }
  * { ... }
  + article { ... }
  > p { ... }
  ~ main { ... }
}

一些例子

让我们来看一些例子,以更好的展示CSS Nesting的工作。

1
2
3
4
5
6
7
<form>
  <label for="name">Name:
    <input type="text" id="name" />
  </label>
  <label for="email">email:</label>
  <input type="text" id="email" />
</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
input {
  border: tomato 2px solid;
}
label {
  font-family: system-ui;
  font-size: 1.25rem;
  input {
    border: blue 2px dashed;
  }
}

结果:

Example 1

我们看到Name对应的输入框应用了嵌套的 label input 样式,email对应的输入框使用了非嵌套的input样式。

同级选择器

1
2
3
<h2>Heading</h2>
<p>This is the first paragraph.</p>
<p>This is the second paragraph.</p>
1
2
3
4
5
6
7
h2 {
  color: tomato;
  + p {
    color: white;
    background-color: black;
  }
}

效果如下:

example2

组合选择器

1
2
<p class="foo">This is Green.</p>
<p class="foo bar">This is Red.</p>
1
2
3
4
5
6
7
.foo {
  color: green;
  &.bar {
    font-size: 1.5rem;
    color: red;
  }
}

效果如下

example3

这里需要注意 &.bar&和类选择器.bar之间是没有空格的。如果有空格就变成了子元素选择器了。

附加嵌套选择器

这个比较有意思,可以把嵌套的写法变成前置的父选择器

1
2
3
4
5
6
.foo {
  /* .foo styles */
  .bar & {
    /* .bar .foo styles */
  }
}

这个会变成 .bar .foo.foo 会变成子元素选择器

伪类

1
2
3
4
5
6
a {
  color: blue;
  &:hover {
    color: lightblue;
  }
}

&和后面的 :hover 之间没有空格,相当于 a:hover

注意

下面的代码在Sass当中是被允许的:

1
2
3
4
.foo {
  color: blue;
  &Bar { color: red; }
}

但是这种情况在CSS当中是不支持的

总结

CSS Nesting还处于非常早期阶段,目前还没有带来太多事实上的改变,浏览器的全面支持还需要时日,从Sass和Less再回到CSS的写法好像也不是太现实。可能在以后的某天Sass和Less等CSS预编译器,把编译后的代码生成为嵌套样式,以减少编译后的文件大小。

参考资料

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting
  2. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting
  3. https://caniuse.com/?search=CSS%20nesting
  4. https://drafts.csswg.org/css-nesting/