likes
comments
collection
share

学习 CSS At Rules 原生作用域 — @scope

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

CSS 社区模块化方案

概述简介

在前端快速的发展中, CSS 一直缺乏模块化的概念。由于 CSS 是根据选择器进行全局元素的匹配,它没有作用域可言。但随着项目越来越大,参与的人越来越多,命名冲突的问题日趋严重。于是 CSS 社区逐渐诞生了相应的模块化解决方案:Atomic CSSOOCSSBEMSMACSSITCSSCSS Modules 以及 CSS-In-JS

模块化分类

  • CSS Namespace: 通过人工约定命名规则
  • CSS Modules: 一个 CSS 文件,一个独立的模块
  • CSS-In-JS: 在 Javascript 中写 CSS

学习 CSS At Rules 原生作用域 — @scope

CSS 原生作用域方案

上述中,我们讲解了来自于 CSS 社区的模块化方案,但它们都需要额外的工具或者语法,对于小型项目来说,使用起来还是比较麻烦。但现在有了 CSS 原生作用域的提案,它提供了一种新语法 @scope 来实现局部作用域,或许 CSS 样式隔离的新时代即将到来。 (确切来说,是选择器隔离)

概念说明

来自 https://drafts.csswg.org/css-cascade-6/#at-ruledef-scope

A scope is a subtree or fragment of a document, which can be used by selectors for more targeted matching. A scope is formed by determining:

  • The scoping root node, which acts as the upper bound of the scope, and optionally:
  • The scoping limit elements, which act as the lower bounds.

An element is in scope if:

  • It is an inclusive descendant of the scoping root, and
  • It is not an inclusive descendant of a scoping limit.

作用域可以是 document 的子树或片段,选择器使用它进行更有针对性的匹配。作用域的范围通过如下两点确定:

  • 作用域根节点,它作为作用域的上限
  • 作用域限制元素,它作为作用域的下限(可选)

如果同时满足以下两种情况,则元素在作用域范围中:

  • 它是作用域根节点的 包容性后代
  • 它不是作用域限制元素的 包容性后代

语法定义

作用域样式属于 CSS At Rules 中一种,在 CSS 语法中使用 @scope 进行描述,它声明了与一组样式规则关联的作用域根节点和作用域限制元素。 它具有近度优先的特性 (Proximity precedence)

  /* 定义 */
  @scope [(<scope-start>)]? [to (<scope-end>)]? {
    /* <rule-list> */
  }
  
  
  /* 例 1 */
  @scope (.card) {
    :scope { /* 匹配 .card 自身样式 */ }
  }
  
  /* 例 2 */
  @scope (.card) {
    > img { /* 匹配 .card > img 样式 */ }
    & > img { /* 匹配 .card > img 样式 */ }
    :scope > img { /* 匹配 .card > img 样式 */ }
  }
  
  /* 例 3 */
  @scope (.card) to (.content) {
    img { /* 匹配 .card 到 .content 之间 img 样式, 不包含 img.content */ }  
  }
  
  /* 例 4 */
  @scope (.card) to (:scope > .content) {
    img { /* 匹配 .card img, 但是不匹配 .card > .content img */ }  
  }
  
  • <scope-start> 是一个 CSS 选择器,用于标识作用域根节点
  • <scope-end> 是一个 CSS 选择器,用于标识作用域限制元素
  • <rule-list> 表示作用域声明的样式

注意事项:

在上面 例子2:scope& 有着相同的作用,都匹配了 .card > img 的样式,但其实两者之间还是有很大的区别:

  • :scope 表示匹配的作用域根节点,而 & 则表示匹配作用域根节点的选择器 (可重复使用)。

     @scope (.card) {
      :scope :scope { 
        /* ❌ 不能工作 */ 
      }
      
       & > & { 
         /* 匹配 .card > .card 样式 */  
       }
     }
     
    
  • 它们还有一个区别,是在参与 CSS优先级权重计算时,表现不一样,具体会在下个小节 优先级权重 中进行说明。

优先级权重

@scope 本身不会影响 CSS 优先级权重计算,但是 :scope& 对 CSS优先级有着不同的权重

  • @scope
  @scope (#card) {
    img { /* Specificity = (0,0,1) --- img 为 0,0,1 */ }
  }

  /* 就优先级权重而言,相当于 :where(#card) img */
  • :scope
  @scope (#card) {
    :scope img { /* Specificity = (0,1,1) --- :scope 为 0,1,0; img 为 0,0,1 */ }
  }

  • &
  @scope (#card) {
    & img { /* Specificity = (1,0,1) --- & 为 1,0,0; img 为 0,0,1 */ }
  }

  /* 就优先级权重而言,相当于 :is(#card) img */

应用场景范例

  • @scope (.card) { /* ... */ }

      @scope (.card) {
        img {
          background-color: lightgreen;
          border-color: green;
        }
      }
    

    学习 CSS At Rules 原生作用域 — @scope

  • @scope (.card) to (.card__content) { /* ... */ }

      @scope (.card) to (.card__content) {
        img {
          background-color: lightgreen;
          border-color: green;
        }
      }
    

    学习 CSS At Rules 原生作用域 — @scope

  • @scope { /* ... */ }

    此时作用域根节点为 <style> 的父元素 <div class="card__header">

      <div class="card">
        <div class="card__header">
          <style>
            @scope {
              img, .img {
                background-color: lightgreen;
                border-color: green;
              }
            }
          </style>
          <h1>Card Title</h1>
          <img src="…" height="32" class="hero">
        </div>
        <div class="card__content">
          <p><img src="…" height="32"></p>
        </div>
      </div>
    

    学习 CSS At Rules 原生作用域 — @scope

浏览器兼容性

目前只有谷歌浏览器 (v118+) 支持了 CSS @scope 特性。不过我相信在不久的将来,主流浏览器会对其有更好的支持度。

学习 CSS At Rules 原生作用域 — @scope

转载自:https://juejin.cn/post/7287547895791878200
评论
请登录