初探 CSS 的级联层(@layer)

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

稍微接触过 CSS 的 Web 开发者,级联(层叠)和继承 是 CSS 领域中的一个非常重要的概念。该功能模块在 W3C 规范中也经历了多个版本的迭代,至今天已有多个版本了(CSS2.2Level3Level4Level5),这也足以说明其在 CSS 中的重要性。

对于 Web 者而言,在编写 CSS 时,必须仔细考虑如何编写和组织代码。特别是在一个大型项目或多人协作开发的项目中,级联很容易给项目开发造成不少的障碍,比如说代码相互覆盖,选择器权重造成样式的冲突等。为了在这些情况下重新获得对级联(层叠)的控制,CSS Cascading and Inheritance Level5 规范中新增了一个新的 CSS 特性,即 @layer 规则(一个新的 @ 规则,也就是大家所说的 at-rule 规则),该规则让 CSS 有了层的概念,可以将 CSS 完全封装起来,以便导入。这意味着模块、脚本或其他任何导入你的项目的东西都可以有完全独立的 CSS,从而解决了样式相互覆盖的老问题,也解决了选择器权重造成的样式冲突问题。它还可以让我们更灵活地使用用自定义导入语句,将CSS添加到到页面中。

接下来,让我们来看看它们是什么,我们如何使用它们,以及它们带来了什么好处。

先简单地了解一下CSS 的级联

从《图解CSS:CSS层叠和继承》一文中,可以得知,CSS级联,也被称为 CSS 层叠,正好对应着 CSS(Cascade Style Sheets)中首字母,即 C,也就是 Cascade

主要用来解决应用于同一个元素的CSS冲突的算法,即浏览器通过它来决定将哪些 CSS 样式规则应用到一个元素上。比如下面这个示例:

<!-- HTML -->
<input type="password" id="password" style="color: blue;">

/*CSS*/
input {
    color: grey;
}

input[type="password"] {
    color: hotpink !important;
}

#password {
    color: lime;
}

示例中的 <input>style属性,CSS中的样式代码,甚至用户代理客户端(浏览器)给密码框的默认样式都是用来指定其文本颜色的。只不过,最终密码输入框的文本颜色是粉红色(即hotpink),也就是说,带有 !important 的样式规则最终获胜:

为了决定哪个声明(CSS样式规则)会“获胜”(从而被应用到元素上),级联提供了相应的算法。了解级联算法有助于帮助我们理解浏览器是如何解决样式规则冲突,也就是浏览器决定哪个样式规则运用到元素上。级联算法在不同的规范中有不同的描述,在 Level 5中提供了六个不同的级别。在不考虑级联层的情况下,其标准如下:

这些标准的优先级从高到低排列,并且一个接一个地检查,直到确定一个获取的声明。如果在较高的标准上不能确定哪一个属性声明会获胜,级联将转到下一个标准。比如下图所示:

有关于级联和选择器权重更深入的介绍,还可以阅读下面几篇文章:

注意,在 CSS 选择器 Level 4中新增了一些新的伪类选择器,比如 :is():not():has():where()等。他们对选择器权重有着额外的计算方式,其中 :is():not()或者:has() 伪类选择器的权重被其选择器列表参数中最高的权重所取代;:where()伪类选择器权重计算成0。如果你对 CSS 选择器 Level 4 的一些选择器感兴趣的话,可以阅读《初探CSS 选择器Level 4》一文。

控制 CSS 的级联

你可能已经感觉到了 CSS 级联的复杂性。不过也别太担心。因为我们在编写 CSS 代码时,主要是将我们的 CSS 放在一个相同的来源上,即 Author Origin(开发者编写的 CSS 样式)。因此,我们最终会使用选择器权重和顺序作为控制级联的方法。这样一来,时常会碰到:

  • 使用较高权重的选择器来防止你的代码被后面的代码(或别人的代码)覆盖。但这也会引起另一个不良的现象,可能会在代码中新增很多带有 !important 的样式规则,这本身就会引起更多的问题,比如 !important 在 CSS 样式表中随处可见,需要覆盖的时候难以被覆盖
  • 使用较低权重的选择器又很容易被后面的代码(或别人的代码)覆盖。比如你在引入第三方代码库或组件时,自己的代码可能被覆盖

这两个现象也是编写CSS代码,特别是在一个大型项目或多人协作的项目中常出现。也正因为如此,很多初学 CSS 的开发者,觉得 CSS 很烦人,很难维护。为了大家能更好的编写 CSS和维护CSS代码,这些年来整个社区的开发者一直都在致力于提供各种方法来避免这些现象的出现。比如 BEMITCSSOOCSSCSS-in-JSCSS ModulesCSS Scoped等。这些方法论主要倚重于以下两个方面:

  • 以这样的方式构建你的代码,创造某种逻辑顺序,使之适用于大多数情况
  • 依靠类来保持选择器的权重尽可能的低

比如 ITCSS,他就分多个层来组织和管理 CSS的级联:

有关于 ITCSS 更详细的介绍可以阅读《ITCSS: Scalable and Maintainable CSS Architecture》一文。

虽然社区有很多方法来帮助我们编写CSS和掌握CSS的级联,但这些方法并不能百分之百的解决级联给我们带来的麻烦。主要还是:

  • 由于源码顺序仍然起着决定性的作用,所以顺序带来的覆盖和冲突依旧未真正的解决(“所谓的顺序”并未真正的执行)
  • 选择器权重仍然比层的顺序(源码顺序)更重要

也就是说,要真正的解决级联带来的这些问题,还是需要依靠 CSS 的级联层,也就是 CSS 的 @layer 规则。

级联层的简介

在真正进入级联层(@layer)的世界中之前,我们首先要感谢 @TerribleMia设计了级联层,给我们带来这么优秀的 CSS 功能。最初的设计可以参阅《Cascade Layers Explainer》!

级联层是 CSS Cascading and Inheritance Level 5 规范新增的一项 CSS 特性,由@TerribleMia 主导和推进。规范中是这样描述级联层的:

Declarations within each origin and context can be explicitly assigned to a cascade layer. For the purpose of this step, any declaration not assigned to an explicit layer is added to an implicit final layer.Cascade layers (like declarations) are ordered by order of appearance. When comparing declarations that belong to different layers, then for normal rules the declaration whose cascade layer is last wins, and for important rules the declaration whose cascade layer is first wins. -- CSS Cascading and Inheritance Level 5

大致意思就是说,“每个来源(Origin)和上下文(Context)中的 CSS规则都可以被明确的分配到指定的级联层(Layer)内,而没有显式被分配到级联层的 CSS 样式规则则会被添加到一个隐式的级联层中。级联层就像我们写CSS的规则相似,是按照其在代码中出现的先后顺序排列的,排在越后面的级联层权重越大。当比较不在相同级联层的声明时(选择器权重,样式规则都一样),那么对于正常的规则(不带!important样式规则),级联层在最后的声明获胜,而对于重要的规则(带有!important的规则),级联层在前面的声明获胜”。

也就是说,开发者可以通过级联层(使用 @layer规则),将你的 CSS 分成若干个层。这样一来,来源于用户(User Origin)和开发者(Author Origin)的 CSS 规则,开发者可以有权力来平衡他们。简单地说:

级联层提供了一种结构化的方式来组织和平衡单一来源中的CSS规则,最终决定谁获胜!

由于 CSS 的级联层在CSS级联中有着独特的地位,使用它有一些好处,使开发者对级联有更多的控制。CSS的级联层一般位于“Style 属性”(Style Attribute)和 CSS 选择器权重(Specificity)之间,即:

我们接下来跟着规范中提供的一些案例来深入了解 CSS 的级联层,顺便一探其究竟~!

特别声明: 我们这里所说的层和定位中的堆栈层叠(用z-index控制的层)不是同一个概念,千万别混淆了!通过 z-index 分层是指在视觉上控制盒子堆叠顺序(Z轴的位置),级联层是关于构造你的 CSS 代码和控制 CSS的级联(层叠)。有关于控制盒子堆叠更多的介绍,可以阅读《聊聊CSS中的层叠相关概念》和《Web布局:CSS定位和层叠控制》。

我们现在可以使用 CSS 的级联层?

到写这篇文章为止,虽然 CSS 的级联层已发布了 WD 版本,但并不能代表规范中所描述的一切都是一尘不变的,有些功能特性有可能会随着后续的演进有所变化。但对于我们学习它不会有任何的影响。因为在主流浏览器中都努力增加级联层的实验支持。这仍然是实验性的支持,但相对而言浏览器对该特性的支持进度已经非常的好了

虽然 Caniuse 上还是一片飘红,但我们在 Google Chrome(版本 97.0.4690.2(正式版本)canary )、Firefox(94.0+)和 Safari Technology Preview(Safari 15.4, WebKit 17613.1.6.1)等浏览器中开启相应的标记,可以看到 @layer 的使用效果。你需要先将相应浏览器升级到这些版本(或更高版本),然后按下面的方式开启相应的标记。

Google Chrome Canary

打开 Canary 浏览器,在 URL 栏中输入 chrome://flags/ ,在打开的页面的搜索框中搜索 #enable-cascade-layers,在对应的 “Enable CSS Cascade Layers” 对应的下拉框中,选择 Enabled 选项,然后重启浏览器即可:

Firefox

如果你使用的是 Firefox,先在 URL 栏中输入 about:config,在打开页面的搜索框中搜索 layout.css.cascade-layers.enabled,将其值设置为 true之后重启浏览器:

Safari Technology Preview

Safari Technology Preview(这里也简称 Safari 吧),他的开启方式略有不同,可以直接从浏览器的菜单栏中开启。你可以按照 “Develop” » “Experimental Features” » “CSS Cascade Layers”。选中“CSS Cascade Layers” 选项即可:

你可以使用下面这个简单的示例来测试

<!-- HTML -->
<h1 class="title" id="title">CSS @layer</h1>

/* CSS */
@layer base {
    #title {
        color: red;
    }
}

@layer theme {
    .title {
        color: blue;
    }
}

@layer component {
    h1 {
        color: orange;
    }
}

如果你使用上面所说的浏览器,看到h1的文本颜色是orange,那么恭喜你,你可以开始体验 CSS 级联层(@layer)了。如果不是,那你得重新按照上面的步骤开启相应的标记:

不支持的浏览器,看到的文本颜色是白色的。

CSS 级联层的使用

我们还是由简入深,看看 CSS 级联层是如何使用的。先从创建级联层开始吧!

创建级联层

我们可以显式使用 CSS 新增的 @(at-rule)规则来创建级联层,即 @layer。使用 @layer 规则可以用不同的方式来创建级联层。最简单的一种方式:

@layer myLayer {
    /* CSS Code ... */
}

@layer 规则后面的 myLayer 是新创建的级联层名称,可以在大括号{}内放置你与myLayer相关的CSS样式规则。可以像平时编写 CSS规则一样,在这里面放置任何你想要的 CSS规则,比如:

@layer myLayer {
    h1 {
        color: orange;
        animation: slider-left 10s linear alternate infinite;
    }

    @media screen and (max-width: 760px) {
        h1 {
            color: #f36;
        }
    }

    @keyframes slider-left {
        from {
            translate: 100% 0;
        }
        to {
            translate: -100% 0;
        }
    }
}

效果如下

这种创建级联层的方式有一个特点:使用 @layer 定义了带有一个名称的级联层,并立即给该级联层分配了 CSS 样式!。我们再来看第二种创建级联层的方式。

同样在 @layer 规则紧跟一个或多个级联层名称(多个级联层名需要用逗号,分隔开),但不立即分配样式,然后再像上面示例一样,重新使用 @layer + 级联层名称 {} 方式放置 CSS规则。比如:

/* 建立多个级联层 */
@layer framework, override;

@layer framework {
    @keyframes fadeIn {
        from {
            opacity: 0
        }
        to {
            opacity: 1
        }
    }

    h1 {
        color: orange;
    }
}

@layer override {
    @keyframes fadeIn {
        from {
            opacity: 0;
            color: #f36;
        }
        to {
            opacity: 1;
            color: lime;
        }
    }

    h1 {
        color: yellow;
    }
}

.title {
    animation: fadeIn 2s linear alternate infinite;
}

效果如下

剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/css/css-layer.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部