用 @layer 把样式优先级从「比权重」变成「排顺序」

样式失控的根源不是选择器写得不够具体,而是所有人都靠加权重解决问题。级联层让顺序显式化:层与层之间比顺序,层内部才比特异性。

每个长期维护的项目最后都会出现 !important。原因不是有人偷懒,而是加权重的做法本身不可持续:今天加一个类压住旧的,明天就得加两个压住这个。

级联层换了个思路:不再比谁的权重高,而是先声明几组样式的先后次序。

基本用法

@layer reset, base, components, utilities;

@layer base {
  a { color: navy; }
}

@layer utilities {
  .link-muted { color: gray; }
}

只要 utilities 排在 base 后面,.link-muted 就一定赢,哪怕 base 里用的是 a 这样更具体的选择器。

关键规则只有三条:

  1. 先声明顺序的那一行决定一切。 层的优先级由第一次出现的顺序决定,与后面写什么无关
  2. 层之间不看特异性,只看顺序
  3. 层内部照旧比特异性,原来的规则完全不变

第三条很重要:@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 变简单,它只是把「谁赢」从隐式的权重计算换成了显式的一行声明。可见的规则永远比算出来的规则好维护。

← 返回文章列表

评论

…