先记住这个答案
浏览器遇到一个层名时,先检查这个名字是不是第一次出现。如果是第一次出现,就给它分配一个优先级排名;如果之前已经出现过,就把这次写的规则合并到已有的层里,排名不变。所以不管你在文件里写了多少次 @layer components { ... },components 层的优先级始终由它第一次出现的位置决定。
- 顺序由第一次出现的位置决定
- 后续同名声明只追加规则
@layer a, b;预声明锁定顺序- 嵌套层用点号表示层级关系
不预声明时的排序陷阱
如果不写预声明,层的顺序取决于代码里的出现位置。这在多人协作或多文件拼接时很容易出问题。
/* 文件 A:先出现 utilities */
@layer utilities { .mt-4 { margin-top: 1rem; } }
/* 文件 B:后出现 components */
@layer components { .card { margin-top: 0; } }
/* 结果:utilities 先出现排名低,components 后出现排名高 */
/* .card.mt-4 的 margin-top 是 0,因为 components 赢了 */本来你可能希望 utilities 层优先级最高,但因为它被先引入了,优先级反而最低。调换两个文件的引入顺序就会得到不同的结果,这在大型项目里容易埋雷。
预声明锁定顺序
最佳实践是在最顶部写一行预声明,把所有层名和顺序一次性定好。
/* 一行锁定:reset 最低,utilities 最高 */
@layer reset, base, components, utilities;
/* 后面可以按任意顺序填充规则 */
@layer utilities { .hidden { display: none; } }
@layer reset { *, *::before, *::after { box-sizing: border-box; } }
@layer base { body { font-family: system-ui; } }
@layer components { .btn { padding: 8px 16px; } }即使 utilities 层的代码写在最前面,它的优先级仍然最高,因为预声明里它排最后。团队成员随意调整代码位置也不会打乱优先级。
嵌套层的排序规则
层可以嵌套。嵌套层的优先级只在父层内部排序,不会跳出父层。写法上可以用 @layer 嵌套,也可以用点号简写。
@layer framework {
@layer base { p { color: gray; } }
@layer theme { p { color: blue; } }
}
/* 等价于 @layer framework.base 和 @layer framework.theme */framework.base 和 framework.theme 都在 framework 层内部。如果另一个顶层层 app 排在 framework 后面,app 层里的规则优先级比 framework 的两个子层都高,不管子层内部谁赢。
嵌套层同样遵守「首次出现定排名」的规则。第一次提到 framework.base 的位置决定了它在 framework 内部的排名。
容易答错的地方
- 以为后面的
@layer块会提高层的优先级 - 多次打开同一个层只是追加规则,不改变排名。在文件末尾再写一次
@layer reset { ... }不会让 reset 层变成最高优先级。 - 以为预声明里写两遍能改变顺序
@layer a, b, a;里第二次出现的 a 会被忽略,因为 a 已经在第一次出现时被分配了排名。预声明里重复写层名没有意义,也不会报错。
面试官还会怎么问?
@import 引入的文件里声明了层,顺序怎么算?
@import url('lib.css') layer(vendor); 会把整个文件放进 vendor 层。vendor 层的优先级由这行 @import 在样式表中的位置决定。如果在预声明之后、且 vendor 已经在预声明中出现过,那排名就用预声明的。
嵌套层的点号写法和花括号嵌套有区别吗?
功能上没有区别。@layer framework.base { ... } 和 @layer framework { @layer base { ... } } 效果完全一样。点号写法更简洁,适合只往一个子层加规则的情况。
没有预声明的项目想加上,应该怎么做?
在所有 @layer 块之前加一行 @layer 声明列出所有层名。加之前先用浏览器开发工具查看当前的层叠顺序(Chrome 的 Layers 面板),确保预声明的顺序和现有行为一致,否则可能改变样式。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。