PAYATHON 2026

CSS Nesting 中的 .featured & 为什么会匹配同一卡片内的 h2?

数据小许

浏览器会匹配 Card 2。最内层的 & 指代上一层规则匹配的 h2 元素。.featured & 要求这个 h2 有一个 .featured 祖先,而该祖先也可以是满足 .card h2 条件的 .card 元素。

两个条件可以由同一个祖先或不同祖先满足。因此,这条规则可以匹配 <article class="card featured"> 内的标题,但不能一概改写为 .card.featured h2。

逐层理解这里的 &

原生 CSS Nesting 中,& 代表父级样式规则匹配的元素。分析多层嵌套时,要逐层确定它的含义。CSS Nesting 规范草案说明,可以用 :is() 包裹父规则选择器来解释这种关系。

第一层嵌套是:

.card {
  & h2 {
    color: slateblue;
  }
}

这里的 & 对应 .card,标题规则可以写成:

.card h2 {
  color: slateblue;
}

再看内层:

.card {
  & h2 {
    .featured & {
      color: tomato;
    }
  }
}

此时父规则匹配的是 .card h2,最内层规则可以展开为:

.featured :is(.card h2) {
  color: tomato;
}

如果直接把 & 替换成不带 :is() 的 .card h2,结果就是 .featured .card h2。这会额外要求 .featured 位于 .card 外面,改变匹配范围。

为什么同一个 article 能满足条件?

对于原来的结构:

<article class="card featured">
  <h2>Card 2</h2>
</article>

可以分别检查两个条件:

  1. h2 是否匹配 .card h2?是,它有一个 .card 祖先。
  2. 这个 h2 是否有 .featured 祖先?是,同一个 article 也具有 .featured。

这两个条件可以由同一个祖先满足,也可以由不同祖先满足。规则没有要求 .featured 必须位于 .card 外面。

在题目给出的样式中,tomato 规则的 specificity 为 (0, 2, 1),高于基础颜色规则 .card h2 的 (0, 1, 1),因此 Card 2 使用 tomato。

两个 :is() 是否等同于 .card.featured h2?

MDN 示例注释给出的写法是:

:is(.card h2):is(.featured h2)

两个 :is() 之间没有组合符,表示同一个目标元素必须同时匹配 .card h2 和 .featured h2。

这要求同一个 h2 满足两个条件,但两个条件中的祖先不必是同一个元素。例如:

<div class="card">
  <section class="featured">
    <h2>Example</h2>
  </section>
</div>

这个标题匹配 :is(.card h2):is(.featured h2),也匹配原来的嵌套规则,但不匹配 .card.featured h2,因为没有祖先同时具有这两个 class。交换 .card 和 .featured 的内外顺序,标题仍然匹配前两个选择器。

另外,理解 MDN 注释中的“等价”时,需要区分匹配范围和 specificity。对本题而言:

选择器specificity匹配要求
.featured :is(.card h2)(0, 2, 1)标题分别有 .card 和 .featured 祖先,允许是同一个
:is(.card h2):is(.featured h2)(0, 2, 2)与上一行匹配相同的元素
.card.featured h2(0, 2, 1)标题有一个同时具有两个 class 的祖先

两个 :is() 会分别贡献 specificity,所以第二行虽然匹配相同的元素,参与层叠时的权重却不同,不能视为完全等价的替换。

按实际需求选择写法

如果需要保留原规则的匹配范围和 specificity,可以使用平铺形式:

.card h2 {
  color: slateblue;
}

.featured :is(.card h2) {
  color: tomato;
}

如果业务要求是“只有同时带有 card 和 featured 的卡片,其内部标题才变色”,可以明确写成:

.card {
  & h2 {
    color: slateblue;
  }

  &.featured h2 {
    color: tomato;
  }
}

其中 &.featured h2 对应 .card.featured h2。如果要求 .featured 在外、.card 在内的两层祖先结构,则直接使用 .featured .card h2。这几种写法在题目给出的 HTML 中可能呈现相同结果,但对其他 DOM 结构的匹配要求不同。

备注:内容仅供参考。