CSS 嵌套模块 第1级

W3C 工作草案,

关于此文档的更多信息
此版本:
https://www.w3.org/TR/2026/WD-css-nesting-1-20260122/
最新发布版本:
https://www.w3.org/TR/css-nesting-1/
编辑草稿:
https://drafts.csswg.org/css-nesting/
历史记录:
https://www.w3.org/standards/history/css-nesting-1/
反馈:
CSSWG 问题库
规范内联问题
编辑:
Tab Atkins-Bittner (Google)
前任编辑:
Adam Argyle (Google)
建议修改此规范:
GitHub 编辑器
测试套件:
https://wpt.fyi/results/css/css-nesting/

摘要

本模块引入了在一个样式规则内嵌套另一个样式规则的能力,子规则的选择器相对于父规则的选择器。这提高了 CSS 样式表的模块化和可维护性。

CSS 是一种用于描述结构化文档(如 HTML 和 XML)在屏幕、纸张等上的呈现的语言。

文档状态

本节描述了文档在发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可以在W3C 标准与草案索引中找到。

本文档由 CSS 工作组 作为 工作草案 发布,使用 推荐轨道。作为工作草案发布并不意味着 W3C 及其成员的认可。

本文档为草案文档,可能随时被更新、替换或废止。引用本文档时应仅视为进行中的工作,而非最终规范。

请通过在 GitHub 提交问题(推荐方式)提供反馈,标题中包含规范代码 “css-nesting”,例如:“[css-nesting] …评论摘要…”。所有问题和评论都会被存档。或者,反馈也可以发送到(已存档)公共邮件列表 www-style@w3.org。

本文档遵循 2025年8月18日 W3C 流程文档 的规定。

本文档由在 W3C 专利政策 下运作的团队制作。W3C 维护了与团队交付物相关的公开专利披露列表;该页面还包含专利披露说明。个人若实际知晓某项专利且认为其包含核心权利要求,必须根据W3C 专利政策第6节披露相关信息。

1. 引言

本节非规范性。

这个模块描述了在一个样式规则内嵌套另一个样式规则的支持, 允许内部规则的选择器引用外部规则所匹配的元素。 该特性允许将相关样式聚合到 CSS 文档中的单一结构内, 提高可读性和可维护性。

测试

嵌套的一般测试


1.1. 模块交互

该模块引入了扩展 [CSS21] 解析模型的新解析规则。 它引入了扩展 [SELECTORS-4] 模块的选择器。 它扩展并修改了在 [CSSOM-1] 模块中定义的一些 IDL 和算法。

1.2. 值

本规范未定义任何新的属性或值。

2. 说明

本节非规范性。

设想你有一些想以更紧凑的方式编写的 CSS。

.foo {
  color: green;
}
.foo .bar {
  font-size: 1.4rem;
}

使用嵌套(Nesting),你可以这样写:

.foo {
  color: green;
  .bar {
    font-size: 1.4rem;
  }
}

如果你在 Sass 或其他 CSS 预处理器中做过样式嵌套,你会觉得这非常熟悉。

你可以在父样式规则内嵌套任何规则:

main {
  div { ... }
  .bar { ... }
  #baz { ...}
  :has(p) { ... }
  ::backdrop { ... }
  [lang|="zh"] { ... }
  * { ... }
}

默认情况下,子规则的选择器被假定通过后代组合符连接到父规则,但你可以用任何组合符开始嵌套选择器以改变该行为:

main {
  + article { ... }
  > p { ... }
  ~ main { ... }
}

新的 & 选择器让你显式引用父选择器所匹配的元素,因此之前的示例可以写成:

main {
  & + article { ... }
  & > p { ... }
  & ~ main { ... }
}

但你也可以将 & 放在嵌套选择器的其他位置, 以指示父规则和子规则之间的其他类型的关系。 例如,下面的 CSS:

ul {
  padding-left: 1em;
}
.component ul {
  padding-left: 0;
}

可以用嵌套重写为:

ul {
  padding-left: 1em;
  .component & {
    padding-left: 0;
  }
}

同样,& 为你提供了一种方式来表示“这是我希望嵌套选择器放置的位置”。

当你不希望选择器之间有空格时它也很有用。例如:

a {
  color: blue;
  &:hover {
    color: lightblue;
  }
}

这样的代码产生与 a:hover { 相同的结果。 如果没有 &, 你会得到 a :hover {——注意 a 与 :hover 之间的空格——这会导致无法为你的悬停链接设置样式。

你可以嵌套多层——在已嵌套的 CSS 内再次嵌套——任意层级。 你可以将嵌套与容器查询、支持查询、媒体查询和/或层叠层混合使用, 几乎任何东西都可以放在任何东西里面。

3. 嵌套样式规则

样式规则可以嵌套在其他样式规则内。 这些 嵌套样式规则 完全像普通样式规则一样——通过选择器将属性关联到元素——但它们“继承”其父规则的选择器上下文, 允许它们在不重复父选择器的情况下进一步构建父选择器, 并且可以多次这么做。

一个 嵌套样式规则 与普通样式规则完全相同, 不同之处在于它可以使用 相对选择器, 这些相对选择器隐式相对于父规则所匹配的元素。

测试
也就是说, 一个像这样的嵌套样式规则:
.foo {
  color: red;

  a {
    color: blue;
  }
}

是有效的, 并且等价于:

.foo {
  color: red;
}
.foo a {
  color: blue;
}

嵌套规则也可以使用 嵌套选择器 直接引用父规则所匹配的元素, 或使用 相对选择器 语法来指定除“后代”之外的关系。

.foo {
  color: red;

  &:hover {
    color: blue;
  }
}

/* 等价于: */

.foo { color: red; }
.foo:hover { color: blue; }
.foo {
  color: red;

  + .bar {
    color: blue;
  }
}

/* 等价于: */

.foo { color: red; }
.foo + .bar { color: blue; }
测试

3.1. 语法

样式规则的内容现在接受 样式规则 中的 嵌套样式规则 和 at 规则, 以及现有的 声明。

嵌套样式规则 与非嵌套规则的不同之处如下:

嵌套样式规则的精确解析细节定义在 [CSS-SYNTAX-3] 中。

无效的 嵌套样式规则 会被忽略, 其内容亦会被忽略, 但不会使其父规则无效。

包含 相对选择器 的嵌套规则会包含其隐含 嵌套选择器 的特异性。 例如,.foo { > .bar {...}} 与 .foo { & > .bar {...}} 的内部规则具有相同的特异性。

一些生成 CSS 的预处理工具在预处理嵌套时会将选择器作为字符串连接, 允许作者跨嵌套层级构建一个单一 简单选择器。 这有时与像 BEM 之类的层级命名模式一起使用, 以减少文件中选择器内部的重复。

例如,如果一个组件使用类 .foo, 而嵌套组件使用 .fooBar, 在 Sass 中你可以这样写:

.foo {
  color: blue;
  &Bar { color: red; }
}
/* 在 Sass 中,这等价于 */
  .foo { color: blue; }
  .fooBar { color: red; }
*/

这在 CSS 中是不允许的, 因为嵌套不是语法转换, 而是匹配父选择器实际匹配的元素。

同样,选择器 &Bar 在 CSS 中本身就是无效的, 因为 Bar 部分是一个类型选择器, 必须出现在复合选择器的开头。 (也就是说,它必须写作 Bar&。) 所以,幸运的是,CSS 嵌套与预处理器语法之间并不存在重叠。

A selector is said to 包含嵌套选择器 if, when it was parsed as any type of selector, a <delim-token> with the value "&" (U+0026 AMPERSAND) was encountered.

注: 这样明确表述是为了捕获像 :is(:unknown(&), .bar) 的情况, 其中一个未知的选择器 (由于未知,我们无法知道其参数是否打算被解析为选择器) 是选择器中唯一包含 & 的部分。 由于该部分可能是只有新版本浏览器支持的有效选择器, 我们不希望解析依赖于无关的版本问题, 因此我们仍然将其视为 包含嵌套选择器。

If a <forgiving-selector-list> has an item that 包含嵌套选择器 but is invalid, that item is preserved exactly as-is rather than being discarded. (This does not change the matching behavior of the selector—​an invalid selector still fails to match anything—​just the serialization of the selector.)

测试

上面那段在我们把 & 本身移动到选择器模块时需要移到“选择器”部分; 我在这里为方便做了临时修补。

3.2. 示例

/* & 可以单独使用 */
.foo {
  color: blue;
  & > .bar { color: red; }
  > .baz { color: green; }
}
/* 等价于
  .foo { color: blue; }
  .foo > .bar { color: red; }
  .foo > .baz { color: green; }
*/


/* 或者在复合选择器中,
   精化父选择器 */
.foo {
  color: blue;
  &.bar { color: red; }
}
/* 等价于
  .foo { color: blue; }
  .foo.bar { color: red; }
*/

/* 列表中的多个选择器都相对于父选择器 */
.foo, .bar {
  color: blue;
  + .baz, &.qux { color: red; }
}
/* 等价于
  .foo, .bar { color: blue; }
  :is(.foo, .bar) + .baz,
  :is(.foo, .bar).qux { color: red; }
*/

/* & 可以在单个选择器中使用多次 */
.foo {
  color: blue;
  & .bar & .baz & .qux { color: red; }
}
/* 等价于
  .foo { color: blue; }
  .foo .bar .foo .baz .foo .qux { color: red; }
*/

/* & 不必位于选择器的开头 */

.foo {
  color: red;
  .parent & {
    color: blue;
  }
}
/* 等价于
  .foo { color: red; }
  .parent .foo { color: blue; }
*/

.foo {
  color: red;
  :not(&) {
    color: blue;
  }
}
/* 等价于
  .foo { color: red; }
  :not(.foo) { color: blue; }
*/

/* 但是如果你使用相对选择器,
  会自动隐含一个初始的 & */

.foo {
  color: red;
  + .bar + & { color: blue; }
}

/* 等价于
  .foo { color: red; }
  .foo + .bar + .foo { color: blue; }
*/

/* 有点荒谬,但 & 也可以单独使用。 */
.foo {
  color: blue;
  & { padding: 2ch; }
}
/* 等价于
  .foo { color: blue; }
  .foo { padding: 2ch; }

  // 或者

  .foo {
    color: blue;
    padding: 2ch;
  }
*/

/* 再次说明,虽然荒谬,但可以重复使用。 */
.foo {
  color: blue;
  && { padding: 2ch; }
}
/* 等价于
  .foo { color: blue; }
  .foo.foo { padding: 2ch; }
*/

/* 父选择器可以任意复杂 */
.error, #404 {
  &:hover > .baz { color: red; }
}
/* 等价于
  :is(.error, #404):hover > .baz { color: red; }
*/

.ancestor .el {
  .other-ancestor & { color: red; }
}
/* 等价于
  .other-ancestor :is(.ancestor .el) { color: red; }

/* 嵌套选择器本身也可以很复杂 */
.foo {
  & :is(.bar, &.baz) { color: red; }
}
/* 等价于
  .foo :is(.bar, .foo.baz) { color: red; }
*/

/* 多层嵌套会“叠加”选择器 */
figure {
  margin: 0;

  > figcaption {
    background: hsl(0 0% 0% / 50%);

    > p {
      font-size: .9rem;
    }
  }
}
/* 等价于
  figure { margin: 0; }
  figure > figcaption { background: hsl(0 0% 0% / 50%); }
  figure > figcaption > p { font-size: .9rem; }
*/

/* 与层叠层(Cascade Layers)一起使用的示例 */
@layer base {
  html {
    block-size: 100%;

    body {
      min-block-size: 100%;
    }
  }
}
/* 等价于
  @layer base {
    html { block-size: 100%; }
    html body { min-block-size: 100%; }
  }
*/

/* 嵌套层叠层的示例 */
@layer base {
  html {
    block-size: 100%;

    @layer support {
      body {
        min-block-size: 100%;
      }
    }
  }
}
/* 等价于
  @layer base {
    html { block-size: 100%; }
  }
  @layer base.support {
    html body { min-block-size: 100%; }
  }
*/

/* 与作用域(Scoping)一起使用的示例 */
@scope (.card) to (> header) {
  :scope {
    inline-size: 40ch;
    aspect-ratio: 3/4;

    > header {
      border-block-end: 1px solid white;
    }
  }
}
/* 等价于
  @scope (.card) to (> header) {
    :scope { inline-size: 40ch; aspect-ratio: 3/4; }
    :scope > header { border-block-end: 1px solid white; }
  }
*/

/* 嵌套作用域的示例 */
.card {
  inline-size: 40ch;
  aspect-ratio: 3/4;

  @scope (&) to (> header > *) {
    :scope > header {
      border-block-end: 1px solid white;
    }
  }
}

/* 等价于
  .card { inline-size: 40ch; aspect-ratio: 3/4; }
  @scope (.card) to (> header > *) {
    :scope > header { border-block-end: 1px solid white; }
  }
*/

3.3. 嵌套其他 at 规则

除了 嵌套样式规则, 本规范还允许在 样式规则 内放置 嵌套组规则:任何其主体包含 样式规则 的 at 规则也可以嵌套在一个 样式规则 内,除非另有说明。

以这种方式嵌套时, 嵌套组规则 块的内容 按照 <block-contents> 进行解析,而不是 <rule-list>:

具体地,这些规则能够作为 嵌套组规则:
测试

此类 嵌套组规则 的含义和行为在其他方面保持不变, 除非另有说明。

例如,下面的条件嵌套是有效的:
/* 属性可以直接使用 */
.foo {
  display: grid;

  @media (orientation: landscape) {
    grid-auto-flow: column;
  }
}

/* 等价于: */
.foo {
  display: grid;
}
@media (orientation: landscape) {
  .foo {
    grid-auto-flow: column
  }
}

/* 并且也等价于未嵌套的: */
.foo { display: grid; }

@media (orientation: landscape) {
  .foo {
    grid-auto-flow: column;
  }
}

/* 条件可以进一步嵌套 */
.foo {
  display: grid;

  @media (orientation: landscape) {
    grid-auto-flow: column;

    @media (min-width > 1024px) {
      max-inline-size: 1024px;
    }
  }
}

/* 等价于 */
.foo { display: grid; }
@media (orientation: landscape) {
  .foo {
    grid-auto-flow: column;
  }
}

@media (orientation: landscape) and (min-width > 1024px) {
  .foo {
    max-inline-size: 1024px;
  }
}

/* 嵌套层叠层示例 */
html {
  @layer base {
    block-size: 100%;

    @layer support {
      & body {
        min-block-size: 100%;
      }
    }
  }
}

/* 等价于 */
@layer base {
  html { block-size: 100%; }
}
@layer base.support {
  html body { min-block-size: 100%; }
}

/* 嵌套作用域示例 */
.card {
  inline-size: 40ch;
  aspect-ratio: 3/4;

  @scope (&) {
    :scope {
      border: 1px solid white;
    }
  }
}

/* 等价于 */
.card { inline-size: 40ch; aspect-ratio: 3/4; }
@scope (.card) {
  :scope { border-block-end: 1px solid white; }
}

连续的直接嵌套属性序列会被自动封装到 嵌套声明规则 中。 (这在 CSSOM 中是可观察到的。)

测试

3.3.1. 嵌套 @scope 规则

当 @scope 规则是一个 嵌套组规则 时, 在 <scope-start> 选择器中的 & 指代最近的祖先样式规则所匹配的元素。

也就是说,下面的代码:
.parent {
  color: blue;

  @scope (& > .scope) to (& .limit) {
    & .content {
      color: red;
    }
  }
}

等价于:

.parent { color: blue; }
@scope (.parent > .scope) to (:where(:scope) .limit) {
  :where(:scope) .content {
    color: red;
  }
}
& 选择器在 @scope 规则中行为类似于 :where(:scope) 。

3.4. 混合嵌套规则和声明

当一个样式规则既包含声明 又包含 嵌套样式规则 或 嵌套组规则 时, 三者可以任意混合。 出现在规则之后或规则之间的声明 会被隐式地包裹在 嵌套声明规则 中, 以保留它们相对于其他规则的顺序。

例如, 在下面的代码中:
article {
  color: green;
  & { color: blue; }
  color: red;
}

/* 等价于 */
article { color: green; }
:is(article) { color: blue; }
article { color: red; }

/* 不等价于 */
article { color: green; }
article { color: red; }
:is(article) { color: blue; }

为确定 出现顺序(Order Of Appearance) 的目的, 嵌套 样式规则 和 嵌套组规则 被视为在其父规则之后出现。

例如:
article {
  color: blue;
  & { color: red; }
}

两个声明具有相同的特异性 (0,0,1), 但是嵌套规则被视为在其父规则之后出现, 因此 color: red 声明在级联中胜出。

另一方面,在此示例中:

article {
  color: blue;
  :where(&) { color: red; }
}

在 :where() 伪类会将 嵌套选择器 的特异性降为 0, 因此 color: red 声明现在的特异性为 (0,0,0), 在“出现顺序”被考虑之前就输给了 color: blue 声明。

注: 虽然可以自由地混合声明和嵌套规则, 但这样做会更难阅读并且有些令人困惑, 因为后面的属性会被自动包裹在源文本中并未出现的 嵌套声明规则 中。 为了可读性,建议作者在样式规则中先把所有属性放在前面, 然后再放任何嵌套规则。 (这对较旧的用户代理也稍好一些:由于解析和错误恢复的具体细节, 出现在嵌套规则之后的属性可能会被跳过。)

4. 嵌套选择器:& 选择器

当在 嵌套样式规则 中使用时, 必须能够引用父规则所匹配的元素; 说到底,这正是嵌套的全部意义。 为此,本规范定义了一个新的选择器, 即嵌套选择器, 用法为 & (U+0026 AMPERSAND)。

当在嵌套样式规则的选择器中使用时, 嵌套选择器 表示父规则所匹配的元素。 在任何其他上下文中使用时, 它在该上下文中表示与 :scope 相同的元素 (除非另有定义)。

测试
嵌套选择器 可以通过将其替换为父样式规则的选择器并用 :is() 选择器包裹来进行解糖(desugar)。 例如,
a, b {
  & c { color: blue; }
}

等价于

:is(a, b) c { color: blue; }

嵌套选择器 不能表示伪元素 (与 :is() 伪类的行为相同)。

例如,在下面的样式规则中:
.foo, .foo::before, .foo::after {
  color: red;

  &:hover { color: blue; }
}

其中的 & 只表示由 .foo 匹配的元素; 换言之,它等价于:

.foo, .foo::before, .foo::after {
  color: red;
}
.foo:hover {
  color: blue;
}

我们希望放宽此限制, 但需要同时为 :is() 和 & 一并进行修改, 因为它们是基于相同的底层机制构建的。 (Issue 7433)

嵌套选择器的特异性等于父样式规则选择器列表中各个复杂选择器的最大特异性 (与 :is() 的行为相同), 如果不存在这样的选择器列表则为零。

测试
例如,给定以下样式规则:
#a, b {
  & c { color: blue; }
}
.foo c { color: red; }

那么在如下 DOM 结构中

<b class=foo>
  <c>Blue text</c>
</b>

文本将呈蓝色,而不是红色。 & 的特异性是 #a([1,0,0])和 b([0,0,1]) 中较大的一个, 因此为 [1,0,0], 整个 & c 选择器的特异性为 [1,0,1], 大于 .foo c 的特异性 [0,1,1]。

值得注意的是,这与将嵌套手动展开为非嵌套规则得到的结果不同, 因为在手动展开的情况下,color: blue 声明会由 b c 选择器匹配([0,0,2]), 而不是由 #a c([1,0,1])匹配。

为什么特异性会与非嵌套规则不同?

嵌套选择器 有意采用与 :is() 相同的特异性规则, 即使用其参数中最大的特异性, 而不是跟踪究竟哪一个选择器实际匹配。

这是出于性能原因的必要选择; 如果一个选择器的特异性取决于具体匹配到的方式而有多个可能值, 会使选择器匹配变得非常复杂且更慢。

但这仍未解答根本问题: 为什么我们用 & 基于 :is() 来定义? 一些非浏览器的嵌套类功能实现并不把嵌套解糖为 :is(), 主要因为它们出现在 :is() 出现之前。 它们改为直接展开; 但是这带来了严重的问题, 因为某些(相当常见的)情况会意外地产生巨量的选择器,出现指数级爆炸。

.a1, .a2, .a3 {
  .b1, .b2, .b3 {
    .c1, .c2, .c3 {
      ...;
    }
  }
}

/* 朴素地解糖为 */
.a1 .b1 .c1,
.a1 .b1 .c2,
.a1 .b1 .c3,
.a1 .b2 .c1,
.a1 .b2 .c2,
.a1 .b2 .c3,
.a1 .b3 .c1,
.a1 .b3 .c2,
.a1 .b3 .c3,
.a2 .b1 .c1,
.a2 .b1 .c2,
.a2 .b1 .c3,
.a2 .b2 .c1,
.a2 .b2 .c2,
.a2 .b2 .c3,
.a2 .b3 .c1,
.a2 .b3 .c2,
.a2 .b3 .c3,
.a3 .b1 .c1,
.a3 .b1 .c2,
.a3 .b1 .c3,
.a3 .b2 .c1,
.a3 .b2 .c2,
.a3 .b2 .c3,
.a3 .b3 .c1,
.a3 .b3 .c2,
.a3 .b3 .c3 {...}

这里,三层嵌套, 每层列表中各有三个选择器, 会生成 27 个解糖后的选择器。 向列表中添加更多选择器、增加嵌套层数或使嵌套规则更复杂, 都会使一个相对较小的规则扩展为数兆字节的选择器(或更多!)。

一些 CSS 工具通过启发式丢弃某些变体来避免最坏情况, 因此它们并不需要输出那么多,但仍然可能是正确的, 而这是用户代理无法采用的选项。

使用 :is() 进行解糖可以完全消除这个问题, 代价是使特异性略微变得不那么有用, 经评估这是一个合理的权衡。

嵌套选择器 能够匹配父规则所匹配的那些无特征(featureless) 元素。

虽然在复合选择器中 嵌套选择器 的位置不会改变其行为 (即 &.foo 与 .foo& 匹配相同元素), 现有规则仍然适用:如果存在类型选择器,它必须出现在复合选择器的最前面 (即 &div 是非法的,必须写成 div&)。

测试

5. 嵌套声明规则

出于一些技术性原因, 将样式规则开头出现的属性与穿插在其他规则中的属性区分开来是很重要的。

例如,在下面这两个规则中:
.foo {
  color: red;
  @media (...) {...}
  background: blue;
}

我们需要对 color: red 和 background: blue 做稍微不同的处理。 特别地,在 CSSOM 中, color: red 会作为样式规则的 style 属性暴露出来, 而 background: blue 则需要显示在它的 cssRules 列表中。

为此,CSS 解析会自动将此类属性包裹在一个特殊的子规则中以包含它们。 然而,如果我们将它们包裹在带有 样式规则 并使用 & 选择器的规则中, 会出现一些不太理想的行为:

例如,在
.foo, .foo::before {
  color: red;
  & {
    background: blue;
  }
}

嵌套规则不会将 background 属性应用到 .foo::before 元素, 因为 & 无法表示伪元素。

类似地,嵌套在非样式规则中的子声明需要以某种方式作为 规则 在外部暴露, 因为此类规则(如 @media)从未拥有过 style 属性。 这些问题与上面相同。

为了解决所有这些问题, 我们改为将连续的直接嵌套属性序列包裹在一个 嵌套声明规则 中。

除非另有说明, 嵌套声明规则 是一个 嵌套样式规则, 并且在行为上与任何其他样式规则完全相同。 它匹配与其父样式规则完全相同的元素和伪元素, 具有相同的特异性行为。(这在某种程度上类似于使用带有 & 选择器的样式规则,但更加强大,如上所述。)

为什么存在 嵌套声明规则?

最初,本规范将样式规则中的所有声明分组在一起, 将它们“移动”到规则的开头处来处理。 它还自动将嵌套组规则内的原始声明包装到普通的样式规则中, 使用 & 选择器。

我们改为使用 嵌套声明规则 的原因有两点。

首先,使用 & {...} 规则来隐式地将声明包装在一个 嵌套组规则 中会改变行为。 如本注释后面的示例所示, 它会破坏父样式规则包含伪元素的情况, 即使在不包含伪元素的情况下, 它也可能改变嵌套声明的特异性行为。 切换到使用 嵌套声明规则 可以避免这些问题, 使嵌套的 @media/等的行为与*非*嵌套的 @media/等一致。

其次,未来的某些 CSS 特性(尤其是“混入”)的细节如果将交错的声明自动移动到样式规则的开头将无法正确工作。 我们需要保持它们与其他规则的相对顺序, 为了能在 CSSOM 中表示这一点, 必须将它们包装在某种规则中。 如果只是使用普通的 & {...} 规则,同样会出现前述问题, 因此 嵌套声明规则 允许我们在不产生副作用的情况下实现这一点。

例如,在下面的样式片段中:
.foo, .foo::before, .foo::after {
  color: black;
  @media (prefers-color-scheme: dark) {
    & {
      color: white;
    }
  }
}

在暗色模式页面中, .foo 元素的文本颜色会变为白色, 但其 ::before 和 ::after 伪元素将保持黑色, 因为 & 选择器无法表示伪元素。

但是,如果改为这样书写:

.foo, .foo::before, .foo::after {
  color: black;
  @media (prefers-color-scheme: dark) {
    color: white;
  }
}

那么 color: white 会被隐式地包裹在一个 嵌套声明规则 中, 保证与其父样式规则完全相同地匹配, 因此元素及其伪元素在暗色模式页面中都会变为白色文本。

与规则交错的声明会被隐式地包裹在 嵌套声明规则 中, 这使它们成为一个独立样式规则的一部分。 例如,给定如下 CSS:
.foo {
  color: black;
  @media (...) {...}
  background: silver;
}

如果检查 .foo 规则的 CSSOM 对象, 其 style 属性将只包含一个声明: 即 color: black。

background: silver 声明 将出现在隐式创建的 嵌套声明子规则 中, 在 fooRule.cssRules[1].style 可找到它。

测试

6. CSSOM

注: [CSSOM-1] 现在定义 CSSStyleRule 可以拥有子规则。

当在序列化一个 相对选择器(出现在 嵌套样式规则 中)时, 必须将该选择器绝对化, 并插入隐含的 嵌套选择器。

例如,选择器 > .foo 会序列化为 & > .foo.
测试

6.1. The CSSNestedDeclarations Interface

The CSSNestedDeclarations interface 表示一个 嵌套声明规则。

[Exposed=Window]
interface CSSNestedDeclarations : CSSRule {
  [SameObject, PutForwards=cssText] readonly attribute CSSStyleProperties style;
};
style 属性 必须返回该规则的 CSSStyleProperties 对象,且具有以下属性:
computed flag

未设置

readonly flag

未设置

declarations

规则中声明的声明,按指定顺序排列。

parent CSS rule

this

owner node

Null

The CSSNestedDeclarations 规则的序列化行为如同其声明块已被直接序列化一般。

测试

注: 这意味着多个相邻的 嵌套声明规则(例如通过 insertRule 创建) 在序列化并重新解析后会合并为单个规则。

隐私考虑

本规范未报告任何新的隐私考虑。

安全性考虑

本规范未报告任何新的安全性考虑。

7. 变更

自 2023-02-14 工作草案 以来的重大变更:

一致性

文档约定

一致性要求使用描述性断言和 RFC 2119 术语的组合来表达。规范性部分中出现的关键词 “MUST”、 “MUST NOT”、 “REQUIRED”、 “SHALL”、 “SHALL NOT”、 “SHOULD”、 “SHOULD NOT”、 “RECOMMENDED”、 “MAY”、 和 “OPTIONAL” 应按 RFC 2119 所述进行解释。 但是为了可读性,这些词在本规范中并不总是以全大写字母出现。

除明确标记为非规范性的部分、示例和注释外,本规范的所有文本均为规范性内容。 [RFC2119]

本规范中的示例以“for example”引入,或通过 class="example" 与规范性文本区分开,如下所示:

这是一个说明性示例。

说明性注释以“Note”开头,并通过 class="note" 与规范性文本区分开,如下所示:

注,这是一条说明性注释。

告诫(Advisements)为规范性部分,样式上带有强调,使用 <strong class="advisement"> 标示,如下所示: 用户代理必须提供可访问的替代方案。

测试

与本规范内容相关的测试可以像这样的“测试”块中记录。任何这样的块都是非规范性的。


一致性类别

本规范定义了三类一致性:

样式表
一个 CSS 样式表。
渲染器
一个解释样式表语义并呈现使用它们的文档的 用户代理(UA)。
创作工具
一个能够写出样式表的 用户代理(UA)。

如果样式表中使用本模块定义的语法的所有语句都符合通用 CSS 语法和本模块内每个功能的各自语法,则该样式表被视为符合本规范。

渲染器若在按照相应规范解释样式表的同时,通过正确解析并渲染文档支持本规范定义的所有功能,则视为符合本规范。但由于设备限制导致 UA 无法正确渲染文档并不使其被视为不符合规范。(例如,UA 不必在单色显示器上呈现颜色。)

创作工具若能生成语法上符合通用 CSS 语法和本模块中每个功能语法的样式表,并满足本模块中描述的样式表的一切其他一致性要求,则视为符合本规范。

部分实现

为了使作者能够利用向前兼容的解析规则来指定回退值,CSS 渲染器必须将任何其不具备可用支持级别的 at 规则、属性、属性值、关键字和其他语法结构视为无效(并在适当情况下忽略)。特别地,用户代理不得在多值属性声明中选择性地忽略不支持的组件值并保留支持的值:如果任何值被视为无效(不支持的值必须如此),CSS 要求整个声明被忽略。

不稳定与专有特性的实现

为了避免与未来稳定 CSS 特性的冲突,CSS 工作组建议在实现 不稳定 特性和 专有扩展 时遵循 最佳实践 。

非实验性实现

一旦规范达到候选推荐(Candidate Recommendation)阶段,就可以出现非实验性实现,且实现者应在能证明其正确实现了 CR 级别特性时发布不带前缀的实现。

为建立并维持跨实现的 CSS 互操作性,CSS 工作组请求非实验性 CSS 渲染器在发布任何可证明正确实现的 CR 级别特性的无前缀实现之前,向 W3C 提交实现报告(以及必要时用于该实现报告的测试用例)。提交给 W3C 的测试用例将接受 CSS 工作组的审查和修正。

有关提交测试用例和实现报告的更多信息,请参见 CSS 工作组网站 https://www.w3.org/Style/CSS/Test/。 问题请发邮件至 public-css-testsuite@w3.org 邮件列表。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性参考文献

[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 4. 13 January 2022. CR. URL: https://www.w3.org/TR/css-cascade-4/
[CSS-CASCADE-6]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 6. 6 September 2024. WD. URL: https://www.w3.org/TR/css-cascade-6/
[CSS-COLOR-4]
Chris Lilley; Tab Atkins Jr.; Lea Verou. CSS Color Module Level 4. 24 April 2025. CRD. URL: https://www.w3.org/TR/css-color-4/
[CSS-CONDITIONAL-3]
Chris Lilley; David Baron; Elika Etemad. CSS Conditional Rules Module Level 3. 15 August 2024. CRD. URL: https://www.w3.org/TR/css-conditional-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. 24 December 2021. CRD. URL: https://www.w3.org/TR/css-syntax-3/
[CSS21]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS2/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS Object Model (CSSOM). 26 August 2021. WD. URL: https://www.w3.org/TR/cssom-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 11 November 2022. WD. URL: https://www.w3.org/TR/selectors-4/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

说明性参考文献

[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 11 March 2024. CRD. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. 13 January 2022. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-CONDITIONAL-5]
Chris Lilley; et al. CSS Conditional Rules Module Level 5. 30 October 2025. WD. URL: https://www.w3.org/TR/css-conditional-5/
[CSS-PSEUDO-4]
Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 27 June 2025. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-UI-4]
Tab Atkins Jr.; Florian Rivoal. CSS Basic User Interface Module Level 4. 20 January 2026. WD. URL: https://www.w3.org/TR/css-ui-4/

IDL 索引

[Exposed=Window]
interface CSSNestedDeclarations : CSSRule {
  [SameObject, PutForwards=cssText] readonly attribute CSSStyleProperties style;
};

问题索引

上述段落需要在我们把 & 本身移动到选择器模块时移到选择器部分; 我在这里为方便做了临时修补。 ↵
我们希望放宽此限制, 但需要同时为 :is() 和 & 一并进行修改, 因为它们是基于相同的底层机制构建的。 (Issue 7433) ↵