CSS @layer 怎么控制优先级?
CSS @layer 用声明式层级替代了特异性战争——无需 !important 也能精确控级。
- 机制:先声明的层优先级最低,顺序决定一切
- 核心:layer 优先于特异性,子选择器也能覆盖上层
- 反转:
!important反转层级,重要样式反而走底层 - 嵌套:子层用
.访问,写成@layer base.forms { } - 场景:框架 reset + 业务定制分层
- 兼容:2023 起所有现代浏览器原生支持
启动:3 行 @layer
@layer reset, components, utilities;
@layer reset {
button { background: gray; }
}
@layer components {
button { background: blue; }
}
@layer utilities {
button { background: green; }
}
button 最终背景色是 green。utilities 是最后声明的层,覆盖前面所有。
不用 !important,不用堆叠 .btn.btn-primary.active 三层选择器——一行 @layer 声明搞定。
核心机制:声明顺序 = 优先级
@layer a, b, c; 三个名字按从左到右声明。先声明的层 优先级最低,后声明的覆盖前面——跟普通 CSS "后来的赢" 一回事,但作用在 layer 维度。
layer 优先于 specificity
这才是 @layer 的真正卖点:层之间的优先级高于选择器特异性。
@layer base, theme;
@layer base {
* { color: red; } /* 通配符,特异性 0,0,0,0 */
}
@layer theme {
.btn { color: blue; } /* 类选择器,特异性 0,0,1,0 */
}
最终 color 是 blue。base 层的通配符被 theme 层的 .btn 覆盖——尽管特异性更低。
这意味着:可以放心把"全局 reset / 工具类"丢进低优先级层,业务代码写高优先级层,特异性不再重要。
!important 的反转陷阱
!important 翻转优先级——layer 维度也反转:
@layer base, theme;
@layer base {
button { background: red !important; }
}
@layer theme {
button { background: blue !important; }
}
最终 background 是 red——base 层的 !important 反而赢(layer 顺序反过来)。
!important + @layer 的反转是规范明确定义的,不是 bug。设计分层时要么彻底不用 !important,要么明确知道反转会破坏预期优先级。
嵌套层
层里能套层,用 . 访问:
@layer framework {
@layer reset, components;
@layer reset { }
@layer components { }
}
/* 外部引用 */
@layer framework.reset { }
@layer framework.components { }
匿名层(@layer { } 没名字)优先级 = 0(最低),命名层总能覆盖它:
@layer {
button { background: pink; } /* 永远被命名层覆盖 */
}
适合"框架默认 + 用户覆盖"场景——用户一行 @layer user; 就赢。
实战:3 个分层场景
场景 1:Tailwind / Bootstrap + 自定义代码
@layer vendor, app;
@import "tailwindcss";
@layer app {
.my-button { background: hotpink; } /* 总能覆盖 Tailwind */
}
Tailwind v4 / Bootstrap 5 都支持把整个框架塞进低优先级层,业务代码天然胜出。
场景 2:设计系统 token + 业务组件
@layer tokens, components, overrides;
@layer tokens {
:root { --color-brand: #06bdfa; }
}
@layer components {
.btn { background: var(--color-brand); }
}
@layer overrides {
.btn--danger { background: red; }
}
设计师改 token,开发写 components,特殊需求写 overrides——三层分工清晰。
场景 3:第三方 widget 不污染全局
@layer vendor, app;
@layer vendor {
.video-call-popup { /* 三方 CSS,没法改 */ }
}
@layer app {
/* 我们的样式天然比三方优先级高 */
}
如果用 iframe 隔离太重,CSS layer 就是零成本的层级隔离方案。
什么时候用
大型项目(设计系统、微前端、多人协作、第三方 widget)用 @layer 收益最大。小项目三层以下的话,传统特异性管理就够了——layer 引入了额外的心智负担。
References
- MDN @layer —— 完整规范参考
- CSS Cascade 5 Specification —— W3C 规范源
- Tailwind v4 CSS-first config —— Tailwind v4 的
@import "..."集成方式