CSS中@layer 是什么

85 阅读4分钟

一、@layer 是什么?

@layer 是 CSS Cascade Layers(级联层)的核心语法,CSS 官方在 2022 年 2 月发布的规范(CSS Cascading and Inheritance Level 5)中正式引入。
一句话理解:它允许开发者把整条样式表拆成若干个“层”,浏览器先按层的顺序决定胜负,再在层内部按选择器权重、书写顺序等传统规则决定胜负
因此,“进哪一层”比“权重多高”更优先——这是 CSS 自 1996 年以来对级联(cascade)算法的最大一次扩展。


二、解决什么痛点?

  1. 第三方库样式被业务代码污染
    例:你写了 .btn { color:red },后来引入的 UI 库也有 .btn { color:blue },因为库引入顺序靠后,把你的样式覆盖了。
  2. “!important 地狱”
    为了抢优先级,组件库、业务、工具类各自加 !important,维护时不敢删。
  3. CSS 权重“心算”
    .header .nav li.current a::after 只是为了“赢”过另一条样式,结果可读性极差。

有了 @layer,你可以提前约定:
“基础库 < 组件库 < 业务代码 < 实用工具类”,以后无论顺序、权重如何,层序即优先级。


三、基本语法

1. 具名层(推荐)

/* 1. 先声明层顺序,可一次声明多个 */
@layer base, components, utilities;

/* 2. 把样式扔进对应层 */
@layer base {
  body { margin: 0; }
}

@layer components {
  .btn { padding: 4px 8px; }
}

@layer utilities {
  .mt-4 { margin-top: 1rem; }
}

2. 匿名层

@layer { /* 没写名字,浏览器会自动生成一个唯一名字 */
  p { line-height: 1.5; }
}

3. 层嵌套

@layer framework {
  @layer reset, theme, widgets;   /* framework 内部再分 3 个子层 */
}
/* 书写子层样式 */
@layer framework.reset { … }
@layer framework.theme { … }

4. 与 @import 结合

@import url(bootstrap.css) layer(framework);
@import url(app.css) layer(application);

一行即可把整份文件扔进指定层,无需改库源码。


四、级联顺序(Cascade Order)

浏览器判定最终值时,先层外,后层内

  1. Origin & Importance
    (用户代理 !important → 用户 !important → 作者 !important)
  2. Context(@scope、@container 等,略)
  3. Layer(层)
    先按“层顺序”从前往后排;后声明的层 > 先声明的层;未声明的层视为“最后”。
  4. Specificity(选择器权重)
  5. Order of Appearance(书写顺序)

记忆口诀:“层 > 权重 > 顺序” 中的“层”排第一。


五、实战示例

@layer lib, app;

@layer lib {
  .button { background: #1976d2; color: #fff; }
}

@layer app {
  .button { background: tomato; }   /* 虽然权重相同,但 app 层在 lib 之后,所以最终背景是 tomato */
}

如果把层顺序改成 @layer app, lib;,则背景会恢复为 #1976d2与样式书写顺序、选择器权重无关


六、!important 在层里的行为

层内部出现 !important 时,“层顺序”同样优先
举例:

@layer A, B;

@layer A {
  p { color: red !important; }
}

@layer B {
  p { color: blue !important; }
}

最终 pblue,因为 B 层排在 A 后。
只有“同层”才回到传统规则:important 逆序、权重、书写顺序。


七、与 @scope、@container、@media 的混用

  • @layer 可以写在任何 @media@supports 内,也可以反过来。
  • 层顺序以“首次出现”为准
@media screen {
  @layer theme;   /* 第一次出现,顺序生效 */
}
@layer theme {    /* 与上面是同一个层,顺序已固定 */
  body { … }
}

八、浏览器支持 & 兼容策略

  • Chrome/Edge 99+、Firefox 97+、Safari 15.4+ 已完整支持。
  • 旧浏览器会跳过整段 @layer { … },导致样式丢失。
    兼容写法(利用 “未知 @ 规则会被忽略” 的特性):
/* 给新浏览器 */
@layer support {
  .btn { padding: .5rem 1rem; }
}

/* 给旧浏览器:再写一份不在层里的样式,避免裸奔 */
@supports not (at-rule(@layer)) {
  .btn { padding: .5rem 1rem; }
}

或者直接用 PostCSS 插件 postcss-cascade-layers 把层拆成传统权重,自动输出兼容 build。


九、最佳实践小结

  1. 项目初始化先“约层”
    @layer reset, theme, components, utils, overrides;
  2. 第三方库全部进层
    @import url(...bootstrap...) layer(libs.bootstrap);
  3. 业务代码默认放最高层(或 overrides 层),不再用 !important
  4. 工具类(atomic CSS)放最后层,保证总能“赢”。
  5. 避免在层里再写“高权重选择器”,除非确实需要子层内再细分。
  6. 团队 code review 只看“进层”对不对,不再纠结权重计算。

十、一句话总结

@layer 把“优先级”从“权重玄学”变成了“显式分层”,让 CSS 终于拥有了可预测、可维护、可扩展的“模块化级联”能力。
只要记住:“层外先排序,层内再比权重”,你就掌握了这套 2022 以来最重要的 CSS 新机制。