用 @layer 把样式优先级从「比权重」变成「排顺序」
样式失控的根源不是选择器写得不够具体,而是所有人都靠加权重解决问题。级联层让顺序显式化:层与层之间比顺序,层内部才比特异性。
每个长期维护的项目最后都会出现 !important。原因不是有人偷懒,而是加权重的做法本身不可持续:今天加一个类压住旧的,明天就得加两个压住这个。
级联层换了个思路:不再比谁的权重高,而是先声明几组样式的先后次序。
基本用法
@layer reset, base, components, utilities;
@layer base {
a { color: navy; }
}
@layer utilities {
.link-muted { color: gray; }
}
只要 utilities 排在 base 后面,.link-muted 就一定赢,哪怕 base 里用的是 a 这样更具体的选择器。
关键规则只有三条:
- 先声明顺序的那一行决定一切。 层的优先级由第一次出现的顺序决定,与后面写什么无关
- 层之间不看特异性,只看顺序
- 层内部照旧比特异性,原来的规则完全不变
第三条很重要:@layer 不是废掉特异性,而是把它关进每一层的内部。
未分层的样式反而最强
没有写进任何 @layer 的规则,属于「未分层」,优先级高于所有层:
@layer base {
.x { color: navy; }
}
.x { color: red; } /* 未分层,赢 */
这条特性让迁移变得可行:新代码写进层里,旧代码先留在层外,两边可以共存。等旧代码搬完,层外自然就空了。
但要小心 —— 这也是 @layer 踩坑最多的地方:引入层的当天,所有未分层的旧样式会突然压过新样式。要么一次性全搬,要么先从最底层(重置、基础排版)开始。
它解决的是哪一类问题
| 问题 | 原来的做法 | 用了层之后 |
|---|---|---|
| 工具类压不住组件类 | 加权重、加 !important |
把工具类放最后一层 |
| 第三方样式乱入 | 复制一份来改 | 第三方放最前一层 |
| 主题覆盖很难写 | 到处找选择器 | 主题单独一层,排在最末 |
| 顺序依赖 import 位置 | 靠注释叮嘱 | 一行 @layer 声明固定 |
最后一行是最大的收益。 以前样式表的加载顺序决定了结果,而加载顺序藏在构建配置里;现在它变成了源码里看得见的一行。
嵌套写法
层内还可以再分层:
@layer components {
@layer form, button;
}
子层的顺序同样由声明决定。这给了「组件内部也有优先级次序」的表达能力,但层级不宜超过两层 —— 超过之后没人记得住顺序,就又回到靠猜的路上了。
什么时候不该用
- 单页面、样式总量很小的项目:收益抵不过理解成本
- 需要兼容不支持的老浏览器:
@layer在旧浏览器里整段规则会被忽略(不是降级),风险要评估 - 与大量
!important混用:!important会把层顺序整个反转(层越前越强),这条反直觉规则会让人彻底看不清
最后一条值得展开:在 !important 的世界里,先声明的层反而赢。所以引入层的同时应当顺手清掉 !important,两者混在一起比任何一者单独用都更难维护。
级联层没有让 CSS 变简单,它只是把「谁赢」从隐式的权重计算换成了显式的一行声明。可见的规则永远比算出来的规则好维护。

评论
…