likes
comments
collection
share

学习 CSS At Rules 级联层 — @layer

作者站长头像
站长
· 阅读数 15

学习 CSS At Rules 级联层 — @layer

什么是 CSS 级联

drafts.csswg.org/css-cascade…

The cascade takes an unordered list of declared values for a given property on a given element, sorts them by their declaration’s precedence as determined below, and outputs a single cascaded value. ...

The cascade sorts declarations according to the following criteria, in descending order of precedence: 1.Transition declarations 2.Important user agent declarations 3.Important user declarations 4.Important author declarations 5.Animation declarations 6.Normal author declarations 7.Normal user declarations 8.Normal user agent declarations

官方定义

CSS 级联获取给定元素上给定属性声明值的无序列表,并将其按照下面的声明优先级对它们进行排序,并输出单个级联值。

  1. 过渡声明
  2. 重要用户代理声明 (浏览器默认样式 + !important)
  3. 重要用户声明 (浏览器用户样式 + !important)
  4. 重要作者声明 (开发者编写样式 + !important)
  5. 动画声明
  6. 普通作者声明 (开发者编写样式)
  7. 普通用户声明 (浏览器用户样式)
  8. 普通用户代理声明 (浏览器默认样式)

相关说明

  • 其中 Transition 和 Animation 声明的级联规则大家可以不用太关心,一是实际开发中这两类的级联规则很少会跟其他级联规则发生冲突,另一个原因是浏览器的真实表现和规范中定义的不一样 (例:Animation 实际呈现的级联是在 !important 之上)

  • 上述 CSS 优先级中 Author(开发者样式) 部分可以进一步分类,如下图:

学习 CSS At Rules 级联层 — @layer

什么是 CSS 级联层

www.w3.org/TR/css-casc…

In the same way that cascade origins provide a balance of power between user and author styles, cascade layers provide a structured way to organize and balance concerns within a single origin. Rules within a single cascade layer cascade together, without interleaving with style rules outside the layer.

官方定义

正如级联源提供用户和作者风格之间的力量平衡一样,级联层提供了一种结构化的方式来组织和平衡单个源中的关注点。单个级联层内的规则级联在一起,而不与层外的样式规则交错。

相关说明

如何理解: 级联层 @layer 可以将某些CSS文件或某些CSS代码块建立一个层级,同层级内的规则将级联在一起。它有点像 PS 中的图层概念,有上下层级之分,上层内容呈现覆盖在下层内容之上。而且在一个图层中的操作 (创建选区,复制、移动、剪切),不会影响其他图层原内容。级联层 @layer 亦是如此,不同的级联层的规则不会交错干涉。但在优先级权重上,上层级联规则覆盖低层级联规则。

应用场景: 在实际前端项目中,我们往往需要引用第三方组件库 (比如 Ant Design VueVant) 进行快速开发或迭代。但有时候根据实际业务需求,这些组件虽然功能是我们需要的,但是 UI样式 却和产品风格不一致,则需要重置某些样式或更换主题风格。例如:

  <!-- Card 组件内 -->
  <div class="card-container">
    <div class="card-header">
      <div class="card-title">Card Title</div>
    </card-header>
    <div class="card-content">
      <slot></slot>
    </div>
  </div>
  /* card.css 文件内 */
  /* 定义了 Card title 字体颜色为黑色 */
  .card-container .card-header .card-title {
     color: #303133;
  }
  

重置 Card 组件 title 字体颜色为红色 (#F34D4D)

  • 没有使用 级联层 @layer 时, 通过增加 CSS 选择器!important 覆盖原组件里的 UI样式。这就需要我们了解组件内部样式级联,当然这并不易于后续 UI样式 维护。

      /* parent.css 文件内 */
      .card-container > .card-header > .card-title {
         color: #F34D4D;
      }
      
      /* global.css 引入样式文件 */
      @import url(./parent.css);
      @import url(./card.css);
    
    
  • 当使用 级联层 @layer 时,我们可以在引用样式的时候,去定义不同的 layer,并指定 layer 之间的顺序,轻而易举实现 CSS优先级 的重置,从而覆盖原组件里的 UI样式

      /* parent.css 文件内 */
      .card-container .card-title {
         color: #F34D4D;
      }
      
      /* global.css 引入样式文件 */
      @layer card, parent; /* 指定 layer 顺序 */
      @import url(./parent.css) layer(parent); /* 指定 layer 名称为 parent */
      @import url(./card.css) layer(card); /* 指定 layer 名称为 card */
    
    

    根据 CSS 优先级权重如下 (越前面权重越大)

    1. inline-style + !important
    2. first @layer + !important
    3. ... @layer + !important
    4. last @layer + !important
    5. no @layer + !important
    6. inline-style
    7. no @layer 
    8. last @layer --- (parent.css)
    9. ... @layer
    10. first @layer --- (card.css)

学习 CSS 级联层 @layer

语法定义

  • 在 @layer 语法中,定义 块级级联层

      /* 创建一个匿名的级联层,缺点: 无法后续追加样式 */
      @layer {
        .padding {
          padding: 0;
        }
      }
      
      
      /* 创建一个名为 common 的级联层,但未分配任何样式。可以后续追加样式 */
      @layer theme, layout, utilities; /* 多个,相当指定了顺序 */
      @layer common;
     
     
      /* 创建一个名为 reset 的级联层,并分配样式 */
      @layer reset {
        .padding {
          padding: 0;
        }
      }
      
      
      /* 允许创建嵌套的级联层,下面两种创建方式等价 */
      @layer reset {
        @layer normal {
          .padding {
            padding: 0;
          }
        }
      }
      
      @layer reset.normal {
        .padding {
          padding: 0;
        }
      }
      
      
      /* 在媒体查询内使用 @layer 时,如果屏幕尺寸更改,则会重新计算图层顺序 */
      @media (min-width: 30em) {
        @layer layout {
          .title { font-size: x-large; }
        }
      }
    
    
  • 在 @import 语法中,定义被引入样式的级联层

      /* 为被引入的样式表分配一个匿名级联层 */
      @import url(reset.css) layer;
      
      
      /* 为被引入的样式表分配一个级联层,命名为 reset */
      @import url(reset.css) layer(reset);
      
    
  • 在 <link> 语法中,定义被引入样式的级联层 (暂不支持,尚在计划阶段)

      <!-- 为被引入的样式表分配一个级联层,命名为 reset -->
      <link rel="stylesheet" layer="reset" href="reset.css">
      
      <!-- 为被引入的样式表分配一个级联层,命名为 reset -->
      <link rel="stylesheet" layer="reset" media="supports(at-rule(@layer))" href="reset.css">
      
    

级联层顺序

  • 默认情况下 (即未显示指定顺序),则级联层按照书写顺序定义排序,其中如果存在重复的同一命名级联层,则只会定义第一次的顺序

        /* 未使用级联层 */
        div { color: white; }
        
        /* 匿名级联层 - No.1 */
        @layer { div { color: blue; } }
    
        /* 命名A1级联层 - No.2 */
        @layer A1 {  div { color: orange; } }
    
        /* 命名A2级联层 - No.3 */
        @layer A2 { div { color: green; } }
    
        /* 命名A1级联层 - No.2,因为之前已经定义 */
        @layer a1 { div { color: gray; } }
        
        /* 匿名级联层 - No.4 */
        @layer { div { color: red; } }
        
        /* 最终应用样式, 未使用级联层样式优先级最高 (未设定 !important) */
        /* blue < orange < gray < green < red < white, 所以应用 color: white; */
      
    
  • 显示指定级联层顺序时, 则会自动将 匿名级联层 排在后面。

        /* 指定级联层顺序 */
        @layer A2, A1;
        
        /* 未使用级联层 */
        div { color: white; }
        
        /* 匿名级联层 - No.3 */
        @layer { div { color: blue; } }
    
        /* 命名A1级联层 - No.2 */
        @layer A1 {  div { color: orange; } }
    
        /* 命名A2级联层 - No.1 */
        @layer A2 { div { color: green; } }
    
        /* 命名A1级联层 - No.2,因为之前已经定义 */
        @layer a1 { div { color: gray; } }
        
        /* 匿名级联层 - No.4 */
        @layer { div { color: red; } }
        
        /* 最终应用样式, 未使用级联层样式优先级最高 (未设定 !important) */
        /* green < orange < gray < blue < red < white, 所以应用 color: white; */
      
    

    最佳实践:使用语句规则预先建立图层顺序, 例如 @layer reset common other;

级联层优先级

级联层中 CSS优先级权重分两种情况,no !important 和 使用 !important 截然不同。在上个小结 级联层顺序 中,我们已经梳理讲解了 no !important 的情况。还是上次例子,我们看下!important 情况:

  /* 指定级联层顺序 */
  @layer A2, A1;

  /* 未使用级联层 */
  div { color: white !important; }

  /* 匿名级联层 - No.3 */
  @layer { div { color: blue !important; } }

  /* 命名A1级联层 - No.2 */
  @layer A1 {  div { color: orange !important; } }

  /* 命名A2级联层 - No.1 */
  @layer A2 { div { color: green !important; } }

  /* 命名A1级联层 - No.2,因为之前已经定义 */
  @layer a1 { div { color: gray !important; } }

  /* 匿名级联层 - No.4 */
  @layer { div { color: red !important; } }

  /* 最终应用样式 */
  /* green > orange > gray > blue > red > white, 所以应用 color: green; */

权重规则如下: (越前面权重越大)

  1. inline-style + !important
  2. first @layer + !important
  3. ... @layer + !important
  4. last @layer + !important
  5. no @layer + !important
  6. inline-style
  7. no @layer 
  8. last @layer
  9. ... @layer
  10. first @layer

CSS选择器权重

在没有 @layer 或 同在一个 @layer 情况下,则看CSS选择器权重,来决定 CSS优先级

  • inline-style + !important
  • css + !important
  • inline-style
  • css 选择器
    • ID 选择器 #app { /* css code*/ }

    • 类选择器、属性选择器、伪类选择器 div.container { /* css code*/ } div[id="app"] { /* css code*/ } div:hover { /* css code*/ }

    • 标签选择器、伪元素选择器 div { /* css code*/ } div::before { /* css code*/ }

    • 通配选择符、关系选择符

    • 继承

例外规则:

:is:not 本身不参与CSS优先级权重的计算, 但是在确定选择器类型计数时,放置在伪类中选择器将作为普通选择器计数 (例 :is(.container):not(.container), 其中 .container 参与CSS优先级权重计算)。

:where(.container) 不仅 :where 本身不参与CSS优先级权重的计算, 就 .container 也不参与CSS优先级权重的计算,这也算是 :where 的一个特性。

浏览器兼容性

目前在主流浏览器环境中兼容性良好(🚧 IE 除外)

学习 CSS At Rules 级联层 — @layer