你以为 !important 是 CSS 样式冲突的终点?今天 @layer 把这件事从架构层彻底变了
你打开一个上线三年的页面,想改一个按钮的颜色。检查元素,.btn-primary 颜色来自一个 !important,往上翻,同一个文件里还有十几处 !important 散落在不同组件上。这不是代码烂——这是特异性战争打到最后,双方都往自己这边扔战术核武的结果。CSS @layer 解决了这个问题,不是靠更聪明地打仗,是直接把这张战场地图重画了。
CSS 特异性战争的本质
从前解决样式冲突只有两条路:把选择器写得更重,或者往后面加 !important。第一条路的终点是你写 .dashboard .sidebar .nav-item .active > a,第二条路的终点是你看到满屏的 !important 并且不敢删任何一行。
BEM、ITCSS、utility-first 框架这些方法论,都是在跟这个系统玩躲猫猫——不是解决它,是绕过它。
@layer 做的事很简单:让你在写代码之前,先告诉浏览器「这些层级的优先级是什么」。浏览器按层执行,不按选择器权重。
/* 声明顺序:第一名优先级最低,最后一名最高 */
@layer reset, base, components, utilities;
声明了顺序之后,任何层的规则都会严格按这个顺序叠加,不管你在 components 里写了几个 class、在 utilities 里写的是单 class。.card .title(0,2,0)打不赢 .text-center(0,1,0),因为 text-center 在 utilities 层,而 utilities 层比 components 层优先级高。
五层方案:生产环境验证过的层叠架构
这个五层结构来自 Wonderflow 设计系统和多个生产案例的验证,已经是业界共识:
@layer reset, tokens, base, components, utilities, overrides;
reset 放 box-sizing、margin: 0 这类重置;tokens 放 CSS 变量定义;base 放全局默认样式;components 放卡片、按钮、表单;utilities 放单用途覆盖类;overrides 放绝对最高优先级的热修。
第三方库的 CSS 可以直接进 reset 层:
@import url('datepicker.css') layer(third-party);
放进来了,你自己的 components 层永远赢,不需要加选择器权重,也不需要 !important。
三个实战模式
第三方库隔离是最常见场景。图表组件、富文本编辑器、日期选择器,它们的 CSS 通常带着高权重选择器进场,你加什么都打不赢。用 @layer 之前:要么给每个选择器前面加前缀,要么用 Shadow DOM 包裹组件。用 @layer 之后:两行代码,第三方样式进低优先级层,你的代码天然赢。
设计系统组件层的用法更关键。Wonderflow 的 Button 组件在 components 层,Snackbar 里的按钮样式需要覆盖它,但 Snackbar 的 Action 按钮不能用 !important。于是 Snackbar 把覆盖写进 overrides 层:
@layer overrides {
.Action {
color: var(--snackbar-bg);
background-color: var(--snackbar-fg);
&:is(:active, :hover) {
opacity: 80%;
}
}
}
因为 overrides 在 components 之后,这条规则天然赢,而且语义清晰——这里就是用来覆盖的,不需要靠 !important 或更重的选择器。
主题覆盖是第三个高价值场景。多主题设计系统(亮色/暗色,品牌变体)可以在 components 层定义默认颜色变量,在 themes 层按 [data-theme="dark"] 覆盖 token 值:
@layer components {
.card { background: var(--card-bg, #ffffff); }
}
@layer themes {
[data-theme="dark"] { --card-bg: #1e1e1e; }
}
主题层在组件层之后,所以 token 替换直接生效,不需要写更具体的选择器。
Tailwind v4 已经在用 @layer
这件事很少人注意到但很重要:Tailwind CSS 从 v4 开始内部已经用 @layer 构建了自己的层叠体系,默认顺序是 theme, base, components, utilities。这意味着你写的 Tailwind 工具类天然在 utilities 层,你的自定义组件样式放在 components 层,工具类天然赢。不需要再研究怎么「让 Tailwind 的优先级更高」。
Adam Arant 在生产环境里直接移除了 Tailwind,改用三层纯 CSS 设计系统,结论是:「原生 CSS 在 2026 年覆盖了团队 2020 年用 Sass、PostCSS 或 Tailwind 做的 90% 的事情」。@layer 是这个判断成立的关键技术原因。
迁移路径:渐进式,一行开始
@layer 的另一个好处是渐进采用。写在任何 @layer 块外面的 CSS(unlayered CSS)优先级高于所有层内样式。这意味着你可以从今天开始,只在顶部加一行声明:
@layer reset, base, components, utilities;
然后把 reset 先放进去,其他保持不动。浏览器会正常渲染,现有代码不受影响。从 reset 开始,逐步把 components、tokens、utilities 迁移进去。每一步都独立生效,不会在中途出现样式崩溃。
注意一件事:一旦开始用 @layer,所有样式最好都进层内。unlayered 空间的优先级最高,如果你在文件底部写了一行 .btn { color: red; } 在层外面,它会盖掉所有层内的 .btn 规则。这个陷阱踩到一次就够了。
结论
@layer 不是 CSS 的新功能。它是 CSS 架构思路的一次升级:从「用更强的武器打赢战争」到「直接画一张没有战争的地图」。从 2022 年 Chrome 99 / Safari 15.4 / Firefox 97 开始,三大引擎已经全部支持。Baseline Widely Available,2026 年不存在浏览器兼容问题。
你今天要做的就一件事:打开你的 main.css,在第一行写 @layer reset, base, components, utilities;,然后把 reset 迁移进去。这个改动不会改变任何视觉,但你的代码从那一天开始,架构变得可解释了。
评论区
登录后可评论。