咱们做前端的,每天都有不可避免的事情------ CSS样式覆盖。
场景你一定不陌生:项目越来越大,引入了UI组件库,又来了几个新同事,大家写的CSS文件越来越多。突然有一天,产品经理让你改一个按钮的颜色,你就写下 .my-button { background-color: blue; }
,刷新一看,没反应!
打开F12,发现你的样式给覆盖了:
css
#app .main-content .card-list .card:nth-child(3) .button { background-color: red; }
怎么办?你的第一反应通常是把自己的选择器也写得更长、更具体,用更高的"权重"把它怼回去。这就是"权重"的开始。
这时候终极方案------!important
------往往就会登场。
!important
可以瞬间解决眼前的冲突,但它带来的副作用是长期的。今天你用一个,明天同事为了覆盖你的,就得用两个。最终,项目里!important
满天飞,CSS变得像一坨屎,彻底失控。
那么解决这个问题,有希望吗?
有。今天,我们就来聊聊CSS官方给我们的分层协议------ @layer
。
"层叠"的规则
在介绍@layer
之前,我们得花一分钟,快速回顾一下CSS"层叠"(Cascade)这个词的本来意思。当多个样式规则都想作用于同一个元素时,它会根据一套严格的标准来决定谁在最上面,谁在最底层。
这个标准,简单说就三条,优先级从上到下:
- 来源和重要性 :浏览器默认样式 < 我们写的样式 < 我们写的带
!important
的样式。 - 权重(Specificity) :这是我们最熟悉的方式。ID选择器(如
#id
) > 类选择器/属性选择器(如.class
,[type="text"]
) > 标签选择器(如div
)。 - 代码顺序:如果上面两条都一样,那简单粗暴,谁写在后面,谁会覆盖前面的。
过去,我们能掌控的,基本就只有第2条和第3条。所以大家只能在"提权重"和"改顺序"这两条路上卷。
新的规则:@layer
好了,@layer
是什么?
你可以把它理解成,CSS官方提供的一种给样式"分层"的工具,就像Photoshop或Figma里的图层一样。
它引入了一个全新的、优先级甚至高于"权重" 的判断标准。
@layer
的核心规则就一句话:层叠顺序(Cascade Layers)的优先级,高于单个选择器的权重。你定义图层的顺序,决定了最终谁胜出。
这听起来有点抽象,我们直接上代码,一看就懂。
假设我们先在CSS文件的顶部,声明定义好我们的图层顺序:
CSS
@layer reset, base, components, utilities;
这行代码的意思是:reset
层的样式最先被考虑(最底层),utilities
层的样式最后被考虑(最顶层)。
现在,我们写两条规则,一条权重很高,但放在了底层的base
里;另一条权重很低,但放在了顶层的utilities
里:
CSS
/* 把它放进 base 图层 */
@layer base {
/* 一个权重很高的选择器 (1个ID + 1个标签) */
#main p {
color: blue;
}
}
/* 把它放进 utilities 图层 */
@layer utilities {
/* 一个权重很低的选择器 (1个类) */
.text-red {
color: red;
}
}
然后我们这么用:
HTML
<div id="main">
<p class="text-red">这段文字会是什么颜色?</p>
</div>
按照老的"权重"规则,#main p
的权重(101)远大于 .text-red
的权重(10),所以文字应该是蓝色的。
但用了@layer
之后,结果是:文字会是红色的!
为什么?因为utilities
这个图层,在我们最开始定义时,就排在了base
图层的后面 。所以,无论base
层里的选择器权重有多高,它都打不过utilities
层里的规则。
这就是@layer
最有意思的地方:它让我们从关注单个选择器,上升到了样式架构层面。
在真实项目中,我们该怎么用@layer
?
理解了原理,我们来看看在实际项目中如何搭建这个分层架构。这是我现在常用的一个分层结构:
CSS
/* 1. 定义所有图层的顺序 */
@layer reset, base, library, components, utilities, overrides;
/* 2. 把不同类型的样式,放进对应的图层 */
/* reset.css 或 normalize.css */
@layer reset {
/* ...重置浏览器的默认样式... */
* { box-sizing: border-box; }
}
/* 基础元素样式 */
@layer base {
body { font-family: sans-serif; }
a { color: #333; }
}
/* 引入第三方UI库,比如Ant Design Vue */
@import url('ant-design-vue/dist/reset.css') layer(library);
@layer library {
/* 你可以写一些覆盖UI库的全局样式 */
}
/* 我们自己的业务组件 */
@layer components {
.card { border: 1px solid #eee; }
.button { padding: 8px 16px; }
}
/* 工具类,比如Tailwind里的 */
@layer utilities {
.text-center { text-align: center; }
.p-4 { padding: 1rem; }
}
/* 最后的"救命稻草"层,用来覆盖一切 */
@layer overrides {
.some-very-specific-case {
/* ... */
}
}
这个结构的好处是:
- 第三方库的样式再也不会"一手遮天"了 。通过
@import ... layer(library)
,我们能把整个UI库的样式都关进一个可控的图层里。 - 工具类的优先级得到了保证 。像
.text-center
这种工具类,我们总是希望它能覆盖掉组件的默认样式,现在把它放在utilities
层,就能轻松实现。 - 我们几乎不再需要
!important
了 。以前需要用!important
的场景,现在大部分都可以通过把覆盖样式写在utilities
或overrides
层来解决,代码变得干净、可预测。
@layer
不是一个小技巧,它是CSS发展史上的一个里程碑。它为我们提供了一个前所未有的处理方式,来管理CSS的复杂性。
它让我们写CSS的思路,从"我该怎么提高这个选择器的权重去覆盖它?",转变成了"我应该把这个样式规则放在哪个图层才最合理?"。

浏览器兼容性方面,截至2025年7月,所有主流浏览器都已支持(简单粗暴统计🙂)。所以,别犹豫了,在你的下一个项目中,尝试用@layer
来构建你的CSS架构吧。
谢谢大家🌼