接手别人的 CSS 代码最怕这件事——@layer 把优先级战争变成目录管理

每次接手别人的 CSS 代码,最头疼的不是样式本身,是那些绕了三层还搞不清的优先级冲突。 specificity 算着算着就乱了,加到最后的解法往往是再加一条 !important,然后问题转移到下一个文件。

@layer 解决这个问题的方式很直接:把样式按功能分组,组之间有明确的高低顺序,上面的覆盖下面的,不需要靠 specificity 硬撑。


先说语法。声明一个 layer 很简单:

@layer base, components, utilities;

@layer base {
  p { margin: 1em; }
}

@layer components {
  .card .title { font-size: 1.5rem; }
}

@layer utilities {
  .text-sm { font-size: 0.875rem; }
}

@layer base, components, utilities; 在最开头先声明层顺序——这里声明了三个层,base 在最底下,utilities 在最上层。三条 @layer 块可以分散在文件各处,CSS 引擎会按声明顺序统一放进对应层级。

渲染结果:utilities 里的规则优先级最高,components 次之,base 最低。同层内 specificity 仍然生效,跨层则只看层级。

实际用法是把第三方 CSS 压到底层。假设你用了 Tailwind + 一个 UI 库,想自定义部分样式:

@layer tailwind-base, library, mine;

@layer tailwind-base {
  /* 第三方重置样式全部进这里 */
}

@layer library {
  /* UI 库样式在这里 */
}

@layer mine {
  /* 所有自定义样式堆在这里,永远在最上层 */
}

这样不需要给选择器加 !important,也不用跟 specificity 赛跑。自己的样式天然赢。

MDN 在重构整个文档站的时候就用过这招。他们有大量历史遗留样式没法改,就用 @layer 把新样式压在上层逐步覆盖旧的。重构过程没有引入回归 bug,维护逻辑也清晰。

Chrome DevTools 现在能直接看到每个选择器属于哪个 layer。打开 Elements 面板,选中一个节点,右侧 Styles 窗格里每条规则前面会显示 layer 名:.card .title @ components 这种格式,一眼就知道这条规则在哪个层级、会不会被上面的覆盖。

落地建议:先在入口文件顶部声明好全站的 layer 顺序,推荐 reset → third-party → framework → components → utilities 五层。然后把每块 CSS 丢进对应层。后续加样式之前,先想清楚”这条属于哪个功能”,再决定放哪个层——不用再数选择器数量或者靠 !important 硬撑了。

浏览器支持情况:主流浏览器全部支持,Chrome 99+、Safari 15.4+、Firefox 97+。IE 当然不支持,但 2026 年了,应该不需要我多说了。

评论区

0 条评论

登录后可评论。