@layer
一个 CSS 的新特性(浏览器支持的版本都比较高,Chrome 要 99)
能够更好的通过声明层级(layer)来解决 CSS 样式覆盖的问题
用来声明一个级联层级(cascade layer),并且可以定义层级的优先权
背景
使用组件库开发的时候,通常需要根据 UI 定制一些颜色、边框之类的 CSS 样式,我们一般都是直接使用优先级更高的选择器进行覆盖
.container .some-button {
}
但这种代码写起来真的头疼,而且又臭又长,有些组件库甚至有全局的 reset 样式,会污染整个文档流的样式
@layer 的作用
**对于组件或者模块的 CSS,我们可以全部写在 @layer 规则中,把自身的优先级降到底部。**这样上层再次覆盖样式就非常简单
Any styles not in a layer are gathered together and placed into a single anonymous layer that comes after all the declared layers, named and anonymous. from MDN
可以理解为任何没有在 @layer
下的样式都会被默认汇集到一个最顶层的匿名 layer,会覆盖其他已经定义的 layer 样式(也就是说没有 layer 的优先级最高,有 layer 的反而低)
具体语法:
@layer layer-name {rules};
@layer layer-name;
@layer layer-name, layer-name, layer-name;
@layer {rules};
直接看个例子吧
可以定义多个层级的优先级,不同层级中有相同的规则时,最后一个胜出
@layer base, special;
@layer special {
.item {
color: rebeccapurple;
}
}
@layer base {
.item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
}
}
上面 special
和 base
两个 layer 中都声明了特定的样式,最终通过 @layer base, special;
这一句告诉 CSS 样式(其中的 color 规则)的顺序 special > base
用 @layer
来指定不同渲染样式的层级的顺序,然后在指定某个 layer 下面的特殊样式进行覆盖。
个人理解(伪代码)
相当于
let @layer = defineLayerStyle(rules, name)
// 定义层级优先级
@layer abc, cbc, bbc;
// 定义很多套/层样式
@layer({ color: red; }, abc);
@layer({ color: green; font-weight: 800; }, bbc);
@layer({ font-weight: 400; line-height: 1.5; }, cbc);
最终浏览器编译成:
function getLayerStyle(name);
// @layer abc, cbc, bbc;
// getLayerStyle(abc);
// getLayerStyle(cbc);
// getLayerStyle(bbc);
{
color: red;
}
{
font-weight: 400;
line-height: 1.5;
}
{
color: green;
font-weight: 800;
}
// 最终样式结果如下
{
color: green;
line-height: 1.5;
font-weight: 800;
}
层级优先级看似是定义了一片 CSS 规则,实际上是针对单条 CSS 规则(比如 color)
让整个 CSS 文件变成 @layer
让这个样式文件整个有一个 layer 叫 lib
使用 @import
时
@import "./zxx.lib.css" layer(lib);
使用 link
时
<!-- zxx-lib.css的样式属于名为 lib 的级联层 -->
<link rel="stylesheet" href="zxx-lib.css" layer="lib" />
<!-- 样式引入到一个匿名级联层中 -->
<link rel="stylesheet" href="zxx-lib.css" layer />
嵌套 layer
@layer outer {
button {
width: 100px;
height: 30px;
}
@layer inner {
button {
height: 40px;
width: 160px;
}
}
}
等价于用 .
连接
@layer outer {
button {
width: 100px;
height: 30px;
}
}
@layer outer.inner {
button {
height: 40px;
width: 160px;
}
}
优先级
@layer 甲 {
p {
color: red;
}
@layer 乙 {
p {
color: green;
}
}
}
@layer 丙 {
p {
color: orange;
}
@layer 丁 {
p {
color: blue;
}
}
}
其中的优先级大小是这样的:丙 > 丙.丁 > 甲 > 甲.乙
兼容性
主流浏览器都支持了(Chrome 99)
revert-layer
首先了解下 revert 关键字,能够让样式规则还原到浏览器自带的样式,通常我们会使用all: revert
这个 CSS 声明让浏览器的 UI 控件还原成默认的样子。
revert-layer
可以让 CSS 属性值还原为上一层 @layer 中设置的同属性值,如果当前 CSS 不在@layer 规则中,或者没有祖先 @layer 规则,则表现类似于 revert 关键字,使用浏览器默认的控件样式。
单 layer 的例子
<ul>
<li class="revert-layer">第1项,颜色是revert-layer</li>
<li class="revert">第2项,作者张鑫旭, revert</li>
<li class="deepcolor">欢迎转发,点赞</li>
</ul>
@layer {
.revert-layer {
color: revert-layer; // 寻找祖先的颜色
}
.revert {
color: revert; // 还原到浏览器自带
}
.deepcolor {
color: deepskyblue;
}
}
多个 layer
@layer base, special; // special > base
@layer special {
.revert-layer {
color: revert-layer; // 还原到 base layer
}
.revert {
color: revert; // 还原到浏览器自带
}
.deepcolor {
color: deepskyblue;
}
}
@layer base {
.revert-layer {
color: deeppink;
}
.revert {
color: deeppink;
}
.deepcolor {
color: deeppink;
}
}
嵌套 layer
@layer outer {
// 外部的 layer 优先级 > 内部 layer
.revert-layer {
color: revert-layer; // 所以会还原到内部的 inner deeppink
}
.revert {
color: revert;
}
.deepcolor {
color: deepskyblue;
}
@layer inner {
.revert-layer {
color: deeppink;
}
.revert {
color: deeppink;
}
.deepcolor {
color: deeppink;
}
}
}
最后
对于第三方组件应用
revert-layer 关键时候还是很有用的。
以后使用第三方组件,都会尽量放在 @layer 中,这样优先级低,样式才能轻易覆盖。
但是,如果希望样式被覆盖后,又继续使用组件里面设置的样式,那只能使用 revert-layer 关键字。
可以这么说,revert 关键是是浏览器默认样式还原,revert-layer 是第三方组件默认样式还原,这样是不是容易理解多了。