原生 CSS 嵌套(Nesting)终于来了!

4 min

1. 那个我们用了十年的“非官方”功能

如果你写过几年前的前端代码,你一定对 Sass 或 Less 不陌生。在这些 CSS 预处理器中,有一个功能几乎是所有开发者的最爱:选择器嵌套 (Nesting)。它允许我们像写 HTML 一样,将子选择器的规则写在父选择器的内部,极大地提升了代码的可读性和组织性。

// Sass 语法
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

多年来,我们一直依赖构建工具将这种语法编译成浏览器认识的普通 CSS。但现在,情况变了。

2. 原生 CSS 嵌套登场

从 2023 年初开始,主流浏览器(Chrome, Safari, Firefox)陆续宣布支持原生的 CSS Nesting Module。这意味着,我们可以直接在 .css 文件里编写嵌套规则,无需任何预处理。

上面的例子用原生 CSS 可以这样写:

/* 原生 CSS 语法 */
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

是的,它看起来和 Sass 完全一样!

3. & 的重要角色

和预处理器一样,& 符号在原生嵌套中也扮演着关键角色,它代表了父选择器。这在处理伪类、伪元素或组合选择器时非常有用。

.card {
  background: white;
  border-radius: 8px;

  /* & 代表 .card */
  &:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  }

  /* & 代表 .card,组合成 .card.dark-mode */
  &.dark-mode {
    background: #333;
  }

  /* & 代表 .card,组合成 .card > .header */
  > .header {
    font-weight: bold;
  }
}

4. 与 Sass 的一个微小但重要的区别

在 Sass 中,你可以直接嵌套类选择器,比如 .card { .title { ... } }。在原生 CSS Nesting 的早期规范中,这是不被允许的,任何嵌套的规则都必须以一个符号(如 &, >, +, ~)开头。

虽然最新的规范放宽了这一限制,允许直接嵌套标签选择器(如 article { h1 { ... } }),但在嵌套类选择器时,为了明确和避免歧义,最佳实践仍然是使用 &

/* 推荐写法 */
.article {
  & .author-name {
    font-style: italic;
  }
}

/* 不推荐的写法 (在某些早期实现或严格解析器中可能无效) */
.article {
  .author-name {
    font-style: italic;
  }
}

使用 & 可以清晰地表达 .author-name.article 的后代。

5. 浏览器支持与未来

截至 2023 年 9 月,所有主流现代浏览器(Chrome 112+, Safari 16.5+, Firefox 117+)均已支持 CSS Nesting。这意味着我们可以开始在生产环境中逐步使用它。

原生 CSS 嵌套的到来,是 Web 平台自身进化的又一个重要里程碑。它减少了我们对构建工具的依赖,让 CSS 本身变得更加强大和富有表现力,也让新入门的前端开发者能够更直观地编写和理解样式代码。