前端开发如何更好的避免级联层CSS@layer样式冲突?
一、什么是级联层 (Cascade Layers)?
1.1 级联层的官方定义
我们参看 Cascading and Inheritance Level 5(13 January 2022) 中 6.4 节所述:
1.2 级联层为了解决什么问题?

我们原来的 'display' 文案是红色,当我们引入了一个第三方组件库,第三方库中有以下样式。
/* 开发者样式 */ .item { color: red; } /* 第三方库 */ #app .item { color: green; border: 5px solid green; font-size: 1.3em; padding: 0.5em; width: 120px; }
/* 开发者样式 */ #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; }
/* 排序层 */@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 什么是级联?
2.2 当前级联的排序标准
- 起源和重要性(Origin and Importance)
- 上下文(Context)
- 样式属性(Element-Attached Styles)
- 层(Layers)
- 特异性(Specificity)
- 出场顺序(又名源代码顺序)(Order of Appearance)
浏览器在确定最终元素样式呈现的时候,会依据这些准则按照优先权从高到低排序,并且会一个一个的检查,直到确定最终样式。
2.3 级联起源(Cascading Origins)
2.3.1 三个核心起源
- 用户代理来源(浏览器内置样式)
- 用户来源(浏览器的用户设置 )
- 作者来源(Web 开发者)
2.3.2 起源的优先级
- 过渡
- 重要的用户代理
- 重要用户
- 重要作者
- 动画
- 普通作者
- 普通用户
- 普通用户代理
越靠前来源的声明优先级越高。过渡和动画我们可以暂时忽略。
2.4 熟悉又陌生的!important
浏览器对具有 'hidden' 类型的 input 输入框设置了默认的展示属性并且将其声明为重要。
input[type=hidden i] { display: none ; }

第二张是样式最终计算结果:隐藏


图片来源:w3.org
下图可以帮助我们直观的理解级联以及级联层在级联中的位置:

图片来源:css-tricks
我们会发现平时操作最多的选择器特异性(selector specificity)只是级联中的一小部分。也轻松地理解了为什么内联样式优先级天然高。同时我们会发现!important 在级联中有特殊地位。他穿插在级联规则的各个阶段并能颠倒优先级。
三、级联层 (CSS@layer) 使用探索
3.1 @layer 是什么?
我们来看 MDN 上的定义:
At-rules 是什么?
3.2 @layer 的句法规则
@layer 的句法如下:
@layer layer-name {rules}@layer layer-name;@layer layer-name, layer-name, layer-name;@layer {rules}
3.3 如何创建级联层
@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; }}
效果如下图:

@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; }}
效果如下:

@layer { .item { color: black; }}
这将创建一个匿名级联层,该层功能与命名层相同。但是使用匿名层有如下缺点:
- 可读性较差:匿名层没有名称,会导致样式表不易阅读和理解。特别是在大型项目中,可能会出现样式不断增加,难以跟踪和管理的问题。
- 难以扩展:如果稍后想要更改特定样式或组合,也会很难找到特定的代码块。
- 不可复用性:匿名层中的样式不能在其他地方重复使用或引用。这样会使样式表更难以管理和维护。
@import url(index.css) layer(index);
同时,也支持匿名引入,例如:
@import url(index.css) layer;
3.4 层的嵌套规则
图层可以嵌套。例如:
@layer base { p { max-width: 70ch; }} @layer framework { @layer base { p { margin-block: 0.75em; } } @layer theme { p { color: #222; } }}
生成的层可以表示为一棵树:
- 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 ; }@layer layer-1 { a { color: red ; } }@layer layer-2 { a { color: orange ; } }@layer layer-3 { a { color: yellow ; } }
任何加上重要声明的样式都以相反的顺序应用
优先级顺序如下:
- !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 目前浏览器支持程度

目前所有现代浏览器均已经支持 @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
五、总结
/* 排序层 */@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@layer)已经历概念提出到到浏览器全面支持的阶段。也许在不久的将来大家都会普遍使用它,期望本文能给大家带来一定帮助。






