使用 CSSNestedDeclarations 改进了 CSS 嵌套

为了修复 CSS 嵌套的一些奇怪问题,CSS 工作组决定向 CSS 嵌套规范中添加 CSSNestedDeclarations 接口。除了这项改进之外,样式规则后面的声明也不再向上移动,此外还进行了一些其他改进。

这些更改从 Chrome 130 版开始生效,并且已可在 Firefox Nightly 132 和 Safari Technology Preview 204 中进行测试。

不使用 CSSNestedDeclarations 的 CSS 嵌套问题

CSS 嵌套的注意事项之一是,最初,以下代码段的运作方式与您最初预期的可能不一致:

.foo {
    width: fit-content;

    @media screen {
        background-color: red;
    }
    
    background-color: green;
}

查看代码后,您可能会认为 <div class=foo> 元素有一个 green background-color,因为 background-color: green; 声明位于最后。但在 130 版之前的 Chrome 中,情况并非如此。在这些版本中,由于不支持 CSSNestedDeclarations,因此该元素的 background-color 为 red

解析 Chrome 130 之前使用的实际规则后,结果如下所示:

.foo {
    width: fit-content;
    background-color: green;

    @media screen {
        & {
            background-color: red;
        }
    }
}

解析后的 CSS 发生了两项更改:

  • background-color: green; 已向上移,以加入其他两个声明。
  • 嵌套的 CSSMediaRule 已重写,以使用 & 选择器将其声明封装在额外的 CSSStyleRule 中。

您在这里会看到的另一项典型更改是,解析器会舍弃不支持的属性。

您可以通过从 CSSStyleRule 中读回 cssText,自行检查“解析后的 CSS”。

为什么要重写此 CSS?

如需了解发生这种内部重写的原因,您需要了解此 CSSStyleRule 在 CSS 对象模型 (CSSOM) 中的表示方式。

在 130 之前的 Chrome 版本中,之前分享的 CSS 代码段会序列化为以下内容:

↳ CSSStyleRule
  .type = STYLE_RULE
  .selectorText = ".foo"
  .resolvedSelectorText = ".foo"
  .specificity = "(0,1,0)"
  .style (CSSStyleDeclaration, 2) =
    - width: fit-content
    - background-color: green
  .cssRules (CSSRuleList, 1) =
    ↳ CSSMediaRule
    .type = MEDIA_RULE
    .cssRules (CSSRuleList, 1) =
      ↳ CSSStyleRule
        .type = STYLE_RULE
        .selectorText = "&"
        .resolvedSelectorText = ":is(.foo)"
        .specificity = "(0,1,0)"
        .style (CSSStyleDeclaration, 1) =
          - background-color: red

在本例中,CSSStyleRule 的所有属性中,以下两个属性相关:

  • style 属性,它是一个表示声明的 CSSStyleDeclaration 实例。
  • cssRules 属性,它是一个 CSSRuleList,用于存储所有嵌套的 CSSRule 对象。

由于 CSS 代码段中的所有声明最终都会位于 CSStyleRule 的 style 属性中,因此会丢失信息。查看 style 属性时,不太清楚 background-color: green 是在嵌套的 CSSMediaRule 之后声明的。

↳ CSSStyleRule
  .type = STYLE_RULE
  .selectorText = ".foo"
  .style (CSSStyleDeclaration, 2) =
    - width: fit-content
    - background-color: green
  .cssRules (CSSRuleList, 1) =
    ↳ …

这会带来问题,因为 CSS 引擎必须能够区分出现在样式规则内容开头的属性与与其他规则交错出现的属性,才能正常运行。

至于 CSSMediaRule 中的声明突然被封装在 CSSStyleRule 中:这是因为 CSSMediaRule 并非旨在包含声明。

由于 CSSMediaRule 可以包含嵌套规则(可通过其 cssRules 属性访问),因此声明会自动封装在 CSSStyleRule 中。

↳ CSSMediaRule
  .type = MEDIA_RULE
  .cssRules (CSSRuleList, 1) =
    ↳ CSSStyleRule
      .type = STYLE_RULE
      .selectorText = "&"
      .resolvedSelectorText = ":is(.foo)"
      .specificity = "(0,1,0)"
      .style (CSSStyleDeclaration, 1) =
        - background-color: red

作者:terry,如若转载,请注明出处:https://www.web176.com/news/frontend/28513.html

(0)
打赏 支付宝 支付宝 微信 微信
terryterry
上一篇 2025年1月14日 下午5:19
下一篇 2025年2月5日 下午5:54

相关推荐

发表回复

登录后才能评论