CSS 嵌套

我们最喜欢的 CSS 预处理器功能之一现已内置到该语言中:嵌套样式规则。

Adam Argyle
Adam Argyle

在嵌套之前,每个选择器都需要与 相互交流。这会导致重复,造成样式表批量和零散编写 体验

之前
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

嵌套后, 可以将其归为一组,以及与其相关的样式规则。

之后
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

请在浏览器中试用此功能

嵌套可以帮助开发者减少重复选择器的需求,同时 相关元素的协同定位样式规则。还有助于样式与 。如果上一个示例中的 .nesting 组件为 则可以删除整个组 相关选择器实例的多个文件。

嵌套功能有助于: - 组织 - 减小文件大小 - 重构

Chrome 112 及 Safari 技术预览版 162 中提供了嵌套功能。

CSS 嵌套使用入门

在本文的其余部分,我们将使用以下演示沙盒来帮助您 直观呈现所选项在此默认状态下,系统不会选择任何内容 一切都可见通过选择各种形状和大小,您可以 练习语法并观察实际运行情况。

由大小不一的圆圈、三角形和正方形组成的彩色网格。

沙盒包含圆形、三角形和正方形。有些为小、中 或大尺寸的图片还有一些可能是蓝色、粉色或紫色的。它们都在.demo内 包含 元素。下面预览了您将在 定位条件。

<div class="demo">
  <div class="sm triangle pink"></div>
  <div class="sm triangle blue"></div>
  <div class="square blue"></div>
  <div class="sm square pink"></div>
  <div class="sm square blue"></div>
  <div class="circle pink"></div>
  …
</div>

嵌套示例

借助 CSS 嵌套,您可以在 另一个选择器。

.parent {
  color: blue;

  .child {
    color: red;
  }
}

在此示例中,.child 类选择器嵌套在 .parent 类选择器。这意味着,嵌套的 .child 选择器将 仅适用于属于 .parent 类的元素的子元素。

也可以使用 & 符号编写此示例,以明确表示 表示父类应放置在何处。

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

这两个示例在功能上是等效的,您可以选择 会随着本文探索更高级的示例而变得更加清晰。

选择圈子

在第一个示例中,任务是添加样式,以便 演示中的圆圈。

如果没有嵌套,CSS 如今可以:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

对于嵌套,有两种有效的方法:

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

结果.demo 内包含 .circle 类的所有元素都如下所示: 模糊不清且近乎不可见:

<ph type="x-smartling-placeholder">
</ph> 彩色形状的网格不再有圆圈,
    它们在后台非常模糊 <ph type="x-smartling-placeholder">
</ph> 试用演示版

选择任意三角形和正方形

此任务需要选择多个嵌套元素,也称为组选择器

不使用嵌套时,CSS 有两种方法:

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

或使用 :is()

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

对于嵌套,有两种有效的方法:

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

结果.demo 中只剩下 .circle 个元素:

<ph type="x-smartling-placeholder">
</ph> 彩色形状的网格中只留下了圆圈,
    所有其他形状几乎都不可见。 <ph type="x-smartling-placeholder">
</ph> 试用演示版

选择大三角形和圆

此任务需要使用复合选择器,其中 元素必须同时具有这两个类,才能被选中。

如果没有嵌套,CSS 如今可以:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

对于嵌套,有两种有效的方法:

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

结果,所有大三角形和圆形都隐藏在 .demo 内:

<ph type="x-smartling-placeholder">
</ph> 彩色网格仅可见中小形状。 <ph type="x-smartling-placeholder">
</ph> 试用演示版
关于复合选择器和嵌套的专业提示

& 符号在此处明确显示了如何连接嵌套 。请参考以下示例:

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

虽然是一种有效的嵌套方式,但结果与您预期的元素不匹配。 原因在于,如果不使用 & 来指定 .lg.triangle, .lg.circle 复合的预期结果,实际结果将为 .lg .triangle, .lg .circle后代选择器

选择除粉色形状以外的所有形状

此任务需要否定函数伪类,其中元素不得 具有指定的选择器。

如果没有嵌套,CSS 如今可以:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

对于嵌套,有两种有效的方法:

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

结果,所有非粉色的形状都隐藏在 .demo 中:

<ph type="x-smartling-placeholder">
</ph> 彩色网格现在是单色的,仅显示粉红色的形状。 <ph type="x-smartling-placeholder">
</ph> 试用演示版
& 助您实现精准与灵活性

假设您希望使用 :not() 选择器定位 .demo。对于以下查询,& 是必需项: :

.demo {
  &:not() {
    ...
  }
}

与之前相比,这样将 .demo:not() 复合为 .demo:not()。 需要 .demo :not() 的示例。在你进行此类尝试时,这条提醒 想要嵌套 :hover 互动。

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

更多嵌套示例

CSS 嵌套规范是 其中包含更多示例。如果您想详细了解 它涵盖了大量有效和无效样本。

接下来的几个示例将简要介绍 CSS 嵌套功能, 了解它引入的广度。

嵌套 @media

移动到样式表的其他区域以查找 用于修改选择器及其样式的媒体查询条件。分散注意力 无法直接在上下文中嵌套条件。

为方便语法,如果嵌套媒体查询只修改样式 当前选择器上下文,则可以使用最简语法。

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

明确使用 & 也可以:

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

此示例展示了扩展语法使用 &,同时定位到 .large 展示其他嵌套功能的卡片将继续工作。

详细了解嵌套 @rules

随处嵌套

到目前为止的所有示例都是继续或附加到之前的上下文。 您可以根据需要完全更改或重新排列上下文。

.card {
  .featured & {
    /* .featured .card */
  }
}

& 符号表示对选择器对象(而非字符串)的引用, 可以放在嵌套选择器中的任意位置。它甚至可以 次数:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

虽然这个示例看起来有点无用,但确实存在 能够重复选择器上下文非常方便。

无效的嵌套示例

有几种无效的嵌套语法场景,可能会让您感到意外 预处理器中有数据。

嵌套和串联

许多 CSS 类命名规范依赖于嵌套能够串联或 将选择器当作字符串附加。这在 CSS 嵌套中不起作用,因为 选择器不是字符串,而是对象引用。

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

如需更深入的说明,请参阅规范

棘手的嵌套示例

嵌套在选择器列表和 :is()

请参考以下嵌套 CSS 代码块:

.one, #two {
  .three {
    /* some styles */
  }
}

这是第一个以选择器列表开头,然后继续进一步嵌套的示例。前面的示例仅以选择器列表结尾。此嵌套示例中没有无效内容,但选择器列表(尤其是包含 ID 选择器的列表)内部嵌套可能存在一个棘手的实现细节。

为了使嵌套的 intent 起作用,任何不是最内部嵌套的选择器列表都将由浏览器使用 :is() 封装。此封装会维护任何编写的上下文中选择器列表的分组。这种分组的副作用是 :is(.one, #two),它会采用括号内选择器中最高分数的特异性。这就是 :is() 一直运行的方法,但是使用嵌套语法时可能会出乎意料,因为它并不是编写的代码。技巧总结如下:与 ID 和选择器列表进行嵌套可能会导致选择特异性非常高的选择器。

为了清晰地回顾这个棘手的示例,我们将按如下方式将上一个嵌套块应用于文档:

:is(.one, #two) .three {
  /* some styles */
}

嵌套在使用 ID 选择器的选择器列表时,请格外小心或教导 linter 警告,该选择器列表中的所有嵌套都具有较高的特异性。

混合嵌套和声明

请参考以下嵌套 CSS 代码块:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

.card 元素的颜色将是 blue

任何混合的样式声明都会提升到顶部,就好像它们是 任何嵌套之前编写的代码如需了解更多详情,请参阅规范

有很多方法可以解决这个问题。以下代码封装了 & 中的三种颜色样式, 按照作者的预期保持级联顺序。颜色 .card 元素将显示为红色。

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

事实上,最好使用 & 封装所有遵循嵌套的样式。

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

功能检测

检测 CSS 嵌套的功能有两种不错的方法:使用嵌套或使用 @supports,用于检查嵌套选择器解析功能。

Bramus 的 Codepen 演示的屏幕截图,其中正在询问您的浏览器是否支持
  CSS 嵌套。该问题下方有一个绿色框,表示支持。

使用嵌套:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

使用 @supports

@supports (selector(&)) {
  /* nesting parsing available */
}

我的同事 Bramus 有一个很棒的 Codepen,它展示了此策略。

使用 Chrome 开发者工具进行调试

目前开发者工具中对嵌套的支持极少。目前,您会发现 样式按预期显示在“样式”窗格中,但跟踪嵌套 及其完整的选择器上下文尚不受支持。我们的设计和计划是 清晰明确地传达信息

Chrome 开发者工具嵌套语法的屏幕截图。

Chrome 113 计划为 CSS 嵌套提供额外的支持。敬请期待!

未来展望

CSS 嵌套仅适用于版本 1。 版本 2 将引入更多语法糖,并且可能会减少 记忆。有许多需求对嵌套解析不受限 或是棘手的时刻

嵌套是对 CSS 语言的一大增强。对内容有创作影响 CSS 架构的方方面面需要从根本上 在能够有效指定版本 2 之前就已探索和理解。

最后,查看演示 结合使用 @scope、嵌套和 @layer。这一切都非常令人振奋!

灰色背景上有一张浅色卡片。卡片有标题和文字
  几个操作按钮和一张赛博朋克风格的图片。