@use+显式前缀是唯一能从编译期切断污染链的方式;@import本质是作用域合并,导致变量覆盖、mixin静默替换、重复css等问题,无法解决spa全局污染。

直接用 @use + 显式前缀,是目前唯一能从编译期切断污染链的方式;@import 无论怎么拆文件、加 BEM,都拦不住变量覆盖和 mixin 静默替换。
为什么 @import 无法解决 SPA 的全局污染
@import 在 Sass 中不是“加载”,而是“作用域合并”——所有 $variable、@mixin、%placeholder 全部平铺进当前上下文,无隔离、无报错、无提示。
- 两个子模块都
@import "vars",且都定义了$z-index-modal,后引入的会直接覆盖前者,运行时才发现弹窗被遮在背后 -
@import "button"和@import "dialog"都含@mixin focus-ring(),最终只保留后者,但button.scss里调用的仍是旧逻辑,IDE 跳转指向错误文件 - Webpack 多入口下重复
@import "_reset.scss",CSS 输出里出现 3 份相同的* { margin: 0; },优先级混乱且体积膨胀
@use 必须带前缀才能访问成员
@use 强制创建私有命名空间,不显式加前缀就等于没声明——这是 Sass 编译器的硬性约束,不是风格建议。
- 写
@use "shared/spacing" as s,就必须用s.$spacing-lg;直接写$spacing-lg会报错Undefined variable - 同一文件多次
@use "utils/functions"不会重复执行,Sass 内部自动去重,无需手动判断 - 第三方模块如
sass:math必须写@use "sass:math";混用@import "sass:math"会导致函数不可见或行为异常 - 想全局解构?只允许
@use "base/vars" as *,且该文件不能含任何@mixin或样式规则,否则编译失败
配合 %placeholder 实现零冗余基础样式复用
比起 @mixin,%placeholder 是更安全的基础样式载体:它不输出 CSS,只在 @extend 时按需注入,天然规避“未调用却已污染”的风险。
-
@mixin reset { margin: 0; padding: 0; }被调用 15 次,就生成 15 份相同规则;%reset { margin: 0; padding: 0; }+@extend %reset只输出一次 -
%sr-only不会出现在最终 CSS 中,HTML 里写class="sr-only"完全匹配不到,杜绝误触发 - 跨文件使用必须先
@use或@forward进当前作用域,天然受模块系统约束,不会“悄无声息地生效” - 禁止对插值选择器使用
%,例如.u-p-#{$n}里不能@extend %p-#{$n},Sass 会报错"%placeholder is not a valid selector"
微前端场景下 UI 库必须改 namespace
Element Plus / Ant Design 等默认类名(如 el-button、ant-btn)在微前端中属于高危污染源——沙箱不拦截静态类名,后加载的 CSS 直接覆盖先加载的。
- Vue 项目:初始化时传入
{ namespace: 'ep' }(Element Plus)或{ prefixCls: 'my-ant' }(Ant Design Vue) - SCSS 层同步改造:新建
element-namespace.scss,用@forward 'element-plus/theme-chalk/src/mixins/config.scss' with ($namespace: 'ep')覆盖变量 - Vite 项目通过
vite.config.ts的css.preprocessorOptions.scss.additionalData全局注入该命名空间配置 - 若用 CSS Modules,则无需改库源码,但需确保所有组件样式文件以
.module.scss结尾,且构建配置已启用模块化处理
真正麻烦的不是语法本身,而是团队里有人还在 @import 第三方包、有人把 @use 当成 @import 的别名来写、还有人试图用 !global 打破命名空间——这些才是大型 SPA 样式失控的起点。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











