共计 8223 个字符,预计需要花费 21 分钟才能阅读完成。
作者:vivo 互联网前端团队 – Zhang Jiqi
本文次要讲述了 CSS 中的级联层(CSS@layer),探讨了级联以及级联层的创立、嵌套、排序和浏览器反对状况。级联层能够用于防止款式抵触,进步代码可读性和可维护性。
一、什么是级联层(Cascade Layers)?
1.1 级联层的官网定义
咱们参看 Cascading and Inheritance Level 5(13 January 2022)中 6.4 节所述:
级联层提供了一种结构化的形式来组织和均衡单个起源中的问题。单个级联层内的规定级联在一起,不与层外的款式规定交织。
开发者能够创立层来体现元素默认值、第三方库、主题、组件、笼罩和其余款式问题,并且可能以显式形式从新排序层级,而无需更改每个层内的选择器或特异性,或依赖源程序来解决跨层的抵触。
单纯看官网定义和概括可能比拟艰涩,上面咱们会联合案例来说分明。
1.2 级联层为了解决什么问题?
简而言之:级联层的呈现就是为了使 CSS 开发者能够更简略间接地管制级联。
咱们来假如日常开发中的一个场景,从场景去了解级联层在解决什么问题。
如下图:
咱们原来的 ’display’ 文案是红色,当咱们引入了一个第三方组件库,第三方库中有以下款式。
/* 开发者款式 */
.item {color: red;}
/* 第三方库 */
#app .item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
width: 120px;
}
就会导致 ’display’ 文案变成绿色。
咱们想要将 ’display’ 文案的色彩由绿色改成红色个别的伎俩是减少选择器特异性(优先级)。比方在开发页面中对开发者款式进行批改:
/* 开发者款式 */
#app div.item {color: red;}
/* 第三方库 */
#app .item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
width: 120px;
}
或者借助级联中出场程序对优先级的影响在用户页面中重写
/* 第三方库 */
#app .item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
width: 120px;
}
/* 开发者款式 */
#app .item {color: red;}
成果如下:
再举个例子:
比方有可能第三方组件写了
a {color: blue;}
那我的项目开发中因为引入这个第三方组件 就会导致款式净化,因为第三方库的款式往往都在我的项目设置的通用款式比方 common.css 后加载。
如果前面想在代码中笼罩某些属性,应用高特异性选择器的语句就可能会导致问题。而后因为有问题就会抉择更高特异性的择器的语句或应用!important,这会使代码变得简短也可能会带来副作用。低特异性选择器的语句很容易被前面呈现在代码中的语句笼罩。在本人的代码之后加载第三方 CSS 时特地会呈现这种问题。
所以级联层就是为了解决以上场景呈现的,级联层在级联中的的地位是在内联款式和选择器特异性之间。当有些 css 申明就是设置要低优先级且不受选择器特异性影响那么应用级联层再适合不过。
使用级联层解决第一个日常开发场景痛点的 css 代码如下:
/* 排序层 */
@layer reset, lib;
/* 通用款式 */
@layer reset {
#app .item {
color: black;
width: 100px;
padding: 1em;
}
}
/* 第三方库款式 */
/* 咱们将第三方库的款式全副放到 lib 层 */
/* 这里个别应用 @import 导入的形式 */
/* 为了示例简略咱们简化了操作 */
@layer lib {
#app .item {
color: green;
border: 5px solid green;
font-size: 1.3em;
width: 130px;
}
}
/* 开发者款式 */
.item {color: red;}
为了晓得为什么下面的 css 代码能解决抵触问题,更好地了解级联层的作用,了解一些景象背地的根因,理解级联层和级联的关系,咱们持续往下看。
二、了解级联层的前提——级联(cascade)
2.1 什么是级联?
CSS 中有两个重要的根底规定,一个是继承,一个是级联。
继承
指的是相似 color,font-family,font-size,line-height 等属性父元素设置后,子元素会继承的个性。
级联
能够简略了解为是 CSS 用来解决要利用于元素的具体款式的算法。也就是基于一些优先级排序输入给给定元素上属性值一个级联值。级联值是级联的后果。
2.2 以后级联的排序规范
咱们参看 Cascading and Inheritance Level 5(13 January 2022)中 6.1 节,
相比于 Cascading and Inheritance Level 4(14 January 2016)中的定义有显著变动。
最重要的变动就是减少了级联层。由此级联排序变成:
- 起源和重要性(Origin and Importance)
- 上下文(Context)
- 款式属性(Element-Attached Styles)
- 层(Layers)
- 特异性(Specificity)
- 出场程序(又名源代码程序)(Order of Appearance)
浏览器在确定最终元素款式出现的时候,会根据这些准则依照优先权从高到低排序,并且会一个一个的查看,直到确定最终款式。
2.3 级联起源(Cascading Origins)
2.3.1 三个外围起源
css 中每个款式规定有三个外围起源,它决定了它进入级联的地位,了解起源优先级是了解级联的要害。
- 用户代理起源(浏览器内置款式)
- 用户起源(浏览器的用户设置)
- 作者起源(Web 开发者)
2.3.2 起源的优先级
Css 申明的起源取决于它来自哪里,重要性在于它是否用!important 申明。
各种起源的优先级按降序排列:
- 过渡
- 重要的用户代理
- 重要用户
- 重要作者
- 动画
- 一般作者
- 普通用户
- 普通用户代理
越靠前起源的申明优先级越高。过渡和动画咱们能够临时疏忽。
2.4 相熟又生疏的 !important
通常作为开发者,!important 会被咱们视为一种减少特异性的办法,用以笼罩内联款式或特异性较高的选择器。
然而!important 设计进去的初衷是作为整体级联中的一个个性,来均衡开发者、用户设置和浏览器内置之间对 css 优先级的影响能力。
默认状况下三者的优先级是:作者起源 \> 用户起源 > 用户代理起源(能够参看上文起源优先级中 6 - 8 的排序)。然而当 css 申明增加!important 之后会使它们的优先程序颠倒(参看上文起源优先级中 2 - 4 的排序)。
如果站在浏览器和用户的角度看!important 提供了在必要时重获优先级控制权的能力,而非只是简略的减少特异性。
举个例子:
浏览器默认样式表蕴含咱们开发者无奈笼罩的重要款式。
浏览器对具备 ’hidden’ 类型的 input 输入框设置了默认的展现属性并且将其申明为重要。
input[type=hidden i] {display: none !important;}
看上面两张图例:
第一张能够看出咱们对具备 ’hidden’ 类型的 input 输入框的展现属性设置成了显示并且申明为重要
第二张是款式最终计算结果:暗藏
从下面的浏览器体现能够看到咱们作为开发者在作者样式表中设置的规定没能笼罩用户代理样式表中的雷同规定。
这验证了下面说的:在级联中!important 会颠倒三大外围起源默认优先程序。
验证的过程中还发现了一个 chrome 控制台这边的 bug,看下面的第一张图例:没失效的规定不划删除线,失效的反而划删除线了。
再看一个官网文档的例子增强一下了解:
图片起源:w3.org
font-size 的值最终是‘12pt’。
因为作者样式表中增加!important 的规定优先权高于用户样式表中一般规定。
text-indent 的值最终是‘1em’。
因为尽管两个样式表都标注了!important,然而标注!important 用户申明优先级大于标注!important 作者申明。
2.5 一张图带你了解级联
下图能够帮忙咱们直观的了解级联以及级联层在级联中的地位:
图片起源:css-tricks
咱们会发现平时操作最多的选择器特异性(selector specificity)只是级联中的一小部分。也轻松地了解了为什么内联款式优先级人造高。同时咱们会发现!important 在级联中有非凡位置。他穿插在级联规定的各个阶段并能颠倒优先级。
三、级联层(CSS@layer) 应用摸索
3.1 @layer 是什么?
咱们来看 MDN 上的定义:
The @layer CSS at-rule is used to declare a cascade layer and can also be used to define the order of precedence in case of multiple cascade layers.
也就是说 @layer 这个 at-rule(AT 规定)用于申明级联层(cascade layer),也能用于定义多个级联层的优先级。
At-rules 是什么?
At-rules是领导 CSS 如何体现的 CSS 语句。它们以 at 符号 ‘ @’ (U+0040 COMMERCIAL AT) 结尾,后跟一个标识符,包含下一个分号 ‘ ;’ (U+003B SEMICOLON) 或下一个 CSS 块之前的所有内容。
咱们开发常见的 at-rule 有 @charset、@media、@font-face、@keyframes 等。
3.2 @layer 的句法规定
@layer 的句法如下:
@layer layer-name {rules}
@layer layer-name;
@layer layer-name, layer-name, layer-name;
@layer {rules}
3.3 如何创立级联层
能够通过多种形式创立级联层。
第一种办法是:创立命名的级联层,其中蕴含该层的 CSS 规定,如下所示:
@layer green {
.item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
width: 120px;
}
}
@layer special {
.item {color: rebeccapurple;}
}
第二种办法是:创立一个命名的级联层而不调配任何款式。这能够是单层,如下所示:
@layer green;
能够一次定义多个层,如下:
@layer green, special
一次定义多个层有什么益处呢?
因为 申明层的初始程序决定了层的优先级。与申明一样,如果在多个层中找到申明,最初定义的层申明将最终失效。看上面代码:
@layer green,special;
@layer green {
#app .item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
width: 120px;
}
}
@layer special {
.item {color: rebeccapurple;}
}
成果如下图:
special 层中 item 款式规定将被利用即便它的特异性低于 green 层中的规定。这是因为 一旦层程序定义实现,就会疏忽选择器特异性。
同样也会疏忽呈现的程序:
咱们申明层名称并设置它们的程序后,能够通过从新申明名称来将 CSS 规定增加到图层。而后将款式附加到层,并且层程序不会更改。比方如下代码尽管 @layer green 从新申明了并在文件前方然而因为程序一开始曾经设置所以字体色彩还是紫色:
@layer green,special;
@layer special {
.item {color: rebeccapurple;}
}
@layer green {
.item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
width: 120px;
}
}
成果如下:
疏忽选择器特异性和代码呈现程序能够让咱们创立更简略的 CSS 选择器,并使代码优雅,因为不用确保选择器具备足够高的特异性来笼罩其余 css 规定,只须要确保它呈现在前面的层中。
第三种办法是:创立一个没有名称的级联层。例如:
@layer {
.item {color: black;}
}
这将创立一个匿名级联层,该层性能与命名层雷同。然而应用匿名层有如下 毛病:
- 可读性较差:匿名层没有名称,会导致样式表不易浏览和了解。特地是在大型项目中,可能会呈现款式一直减少,难以跟踪和治理的问题。
- 难以扩大:如果稍后想要更改特定款式或组合,也会很难找到特定的代码块。
- 不可复用性:匿名层中的款式不能在其余中央重复使用或援用。这样会使样式表更难以治理和保护。
平时咱们尽量避免应用匿名层。但当咱们是款式库的作者,并想将某些 css 代码不被使用者批改能够借助匿名层做到这一点。
第四种办法是:应用 @import。CSS 原生反对 @import 导入其余 CSS 文件。
@import url(index.css) layer(index);
同时,也反对匿名引入,例如:
@import url(index.css) layer;
咱们在应用 @import 时候须要放在除 @charset 之外的款式规定前,否则无奈导入。
可能的第五种形式仍在探讨中:通过元素上的属性。请参阅[css-cascade] Provide an attribute for assigning ato a cascade layer #5853。
3.4 层的嵌套规定
图层能够嵌套。例如:
@layer base {p { max-width: 70ch;}
}
@layer framework {
@layer base {p { margin-block: 0.75em;}
}
@layer theme {p { color: #222;}
}
}
生成的层能够示意为一棵树:
1.base
- framework
- base
2.theme
或能够用扁平列表示意
- base
- framework.base
- framework.theme
要将款式附加到嵌套层,您须要应用以下全名来援用它:
@layer framework {
@layer default {p { margin-block: 0.75em;}
}
@layer theme {p { color: #222;}
}
}
@layer framework.theme {
/* 这些款式会被增加到 framework 层外面的 theme 层 */
blockquote {color: rebeccapurple;}
}
看成果:
3.5 层的排序规定
级联层依照它们申明的程序排序。第一层优先级最低,最初一层优先级最高。然而,未分层的款式具备最高优先级:
/* 未分层 */a {color: green;}
@layer layer-1 {a { color: red;} }
@layer layer-2 {a { color: orange;} }
@layer layer-3 {a { color: yellow;} }
优先级程序如下:
- 未分层款式
- layer-3
- layer-2
- layer-1
看下图示例:
层能够在一个中央被定义图层(以建设图层程序),而后在任何中央增加款式
/* 定义在一个中央 */
@layer my-layer;
/* 其余款式 */
...
/* 在某个中央增加款式 */
@layer my-layer {a { color: red;} }
3.6 加上!important 之后的排序规定
/* 未分层 */ a {color: green !important;}
@layer layer-1 {a { color: red !important;} }
@layer layer-2 {a { color: orange !important;} }
@layer layer-3 {a { color: yellow !important;} }
任何加上重要申明的款式都以相同的程序利用
优先级程序如下:
- !important layer-1
- !important layer-2
- !important layer-3
- !important 未分层款式
看下图示例:
这里咱们看到对应规定在 chrome 浏览器的显示是正确的。然而在开发者控制台中的款式一栏规定显示有问题。应该是 chrome 浏览器开发者控制台的 bug。
3.7 嵌套层的排序规定
@layer layer-1 {a { color: red;} }
@layer layer-2 {a { color: orange;} }
@layer layer-3 {@layer sub-layer-1 { a { color: yellow;} }
@layer sub-layer-2 {a { color: green;} }
/* 未嵌套 */ a {color: blue;}
}
/* 未分层 款式 */ a {color: black;}
优先级程序如下:
- 未分层 款式
-
layer-3
-layer-3 未嵌套
-layer-3 sub-layer-2
-layer-3 sub-layer-1
- layer-2
- layer-1
3.8 媒体查问对层排序的影响
以下 层程序将取决于匹配的媒体条件:
例如:
@media (min-width: 600px) {
@layer layout {
.item {font-size: x-large;}
}
}
@media (prefers-color-scheme: dark) {
@layer theme {
.item {color: red;}
}
}
如果两个媒体查问的规定中匹配一个那么对应的级联层失效。如果两者都匹配,那么图层程序将为 layout, theme 都失效。如果两个都不匹配则不定义层。下图是两者都匹配的场景。
四、当初就能应用级联层吗?
4.1 目前浏览器反对水平
图片起源:developer.mozilla.org
目前所有古代浏览器均曾经反对 @layer 规定。所有浏览器厂商都反对的个性将来肯定比拟实用。
4.2 W3C 激励能够作为日常应用
SS 的标准化流程由 W3C Cascading Style Sheets Working Group (CSSWG)——W3C 层叠款式列表小组以及独立 CSS 专家组成。W3C 自身并不制订规范,而是作为一个论坛式的平台,接管来自小组成员的提交,并通过会议来切磋制订规范,所有的提交以及探讨都是公开通明的,能够在 W3C 网站上看到会议的记录,能够简略分为 4 个大阶段:
- 工作草案(WD)
- 候选人举荐(CR)
- 提议的倡议(PR)
- W3C 举荐(REC)
下图能够帮忙了解:
图片起源:w3.org
W3C 通过状态码示意标准的成熟度。成熟度从低到高排序如下图。
图片起源:w3.org
再看下图:蕴含 layer 概念的规范探讨曾经达到 CR 阶段。
图片起源:w3.org
W3C 激励从 CR 阶段的规范 开始能够作为日常应用。
五、总结
最初,咱们回到通过级联层如何解决“引入了一个第三方组件库导致款式笼罩“的问题上。
css 代码如下:
/* 排序层 */
@layer reset, lib;
/* 通用款式 */
@layer reset {
#app .item {
color: black;
width: 100px;
padding: 1em;
}
}
/* 第三方库款式 */
/* 咱们将第三方库的款式全副放到 lib 层,这里个别应用 @import 导入的形式,为了示例简略咱们简化了操作 */
@layer lib {
#app .item {
color: green;
border: 5px solid green;
font-size: 1.3em;
width: 130px;
}
}
/* 开发者款式 */
.item {color: red;}
咱们将第三方库的款式全副放到 lib 层,将须要重置的一些款式放到 reset 层,本人开发的款式不放入层中(当然你也能够放入到一层而后排序在最初)。由此咱们实现了款式的分层解决了第三方组件库导致款式笼罩的问题,而且做到开发者款式简略不简短。
成果如下:
级联层(CSS@layer)已经验概念提出到到浏览器全面反对的阶段。兴许在不久的未来大家都会广泛应用它,冀望本文能给大家带来肯定帮忙。
参考资料:
- CSS Cascading and Inheritance Level 5
- A Complete Guide to CSS Cascade Layers
- The Future of CSS: Cascade Layers (CSS @layer)
- CSS 必学根底:了解 CSS 中的级联规定
- 详解日后定会大规模应用的 CSS @layer 规定
- W3C Process Document
- Cascade Layers Explainer