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>
可以分别检查两个条件:
h2是否匹配.card h2?是,它有一个.card祖先。- 这个
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 结构的匹配要求不同。
备注:内容仅供参考。
