Sass 官方自 1.30.0 起弃用 @import,因其引发全局污染、变量覆盖、加载顺序失控及 CSS 重复输出;新项目应统一使用 @use 实现命名空间隔离与显式依赖,配合 @forward 封装接口并避免循环引用。

为什么 @import 在新项目里不推荐用了
Sass 官方从 1.30.0 开始正式弃用 @import,它会导致全局作用域污染、难以追踪变量来源、无法控制加载顺序,还让 CSS 输出重复(比如多次 @import 同一个 _variables.scss,里面定义的 $color-primary 可能被覆盖或报错)。
真实场景中,你改了一个 _mixins.scss 里的 fluid-type() 函数,但编译后样式没变——大概率是旧 @import 把老版本混进来了,而且查不到谁先载入的。
实操建议:
- 新项目一律用
@use替代@import - 已有项目迁移时,先检查有没有在多个文件里用
@import重定义同名变量(如$spacing-sm),这类冲突在@use下会直接报错,反而是好事 -
@use默认只暴露以_开头的文件(如@use "src/styles/base"会找_base.scss),路径不用写扩展名和下划线
@use 怎么避免命名冲突又保持可读性
@use 默认把被导入文件的成员挂到命名空间下,比如 @use "styles/vars" as v,之后必须写 v.$color-text 才能访问——这看着啰嗦,但能一眼看出值从哪来。
立即学习 “ 前端免费学习笔记(深入)”;
常见错误:为了省事全用 as *,结果 vars.scss 和 theme.scss 都定义了 $radius,编译直接失败。
实操建议:
- 基础层(颜色、断点、z-index)用简短命名空间,如
@use "src/styles/vars" as v - 功能层(工具类、布局)用语义化别名,如
@use "src/styles/utilities" as util - 真要合并命名空间,用
@forward+with显式透出,而不是靠as *碰运气 - 所有
@use必须放在文件顶部,且不能出现在@media或选择器内部
怎么用 @forward 构建可复用的样式包
@forward 不是简单转发,它是“封装接口”:你可以隐藏内部实现,只暴露想给别人用的部分,还能重命名、加默认值。
典型问题:团队 A 写了个 button.scss,里面依赖 _mixins.scss 和 _vars.scss;团队 B 直接 @use "button" 却发现拿不到 $btn-padding——因为没 @forward 出来。
实操建议:
- 主入口文件(如
index.scss)用@forward "vars" with ($spacing-unit: 4px),既透出变量,又允许调用方覆盖默认值 - 用
@forward "mixins" hide responsive-hover隐藏不希望外部使用的函数 - 避免循环
@forward:A@forwardB,B 又@forwardA,Sass 会报Circular @forward -
@forward后不能跟@use,顺序错了会编译失败
Webpack/Vite 项目里 Sass 模块化要注意什么
构建工具本身不处理 @use 逻辑,全靠 Sass 编译器。但路径解析、缓存、source map 会放大模块化问题。
常见现象:@use "@/styles/typography" 在 Vite 下报 File to import not found,其实是别名解析没配进 Sass 配置里。
实操建议:
- Vite 中需在
vite.config.ts的css.preprocessorOptions.sass.additionalData里补全局变量,但更推荐用@use显式导入,别依赖全局注入 - Webpack 的
sass-loader要升级到 v13+,旧版对@use的路径解析有 bug - 所有
@use路径必须相对于当前文件,不能用绝对路径(@use "/src/styles/vars"是错的) - 开启
sourceMap: true后,Chrome 调试时能看到具体是哪个模块里的font-size生效了,这比以前靠注释定位强得多
模块化的真正难点不在语法,而在于团队对“谁负责定义、谁负责消费、谁有权修改”的约定。哪怕只改一个 $z-index-sticky,也要确认它是不是被 @forward 到了三个子包里——否则改完一处,其他地方就失序了。