想把样式拆模块、做主题、又不想全局变量乱飞?这篇把 SCSS 的四种"导入/组织"方式 一次讲透:@use
、@forward
、Sass 旧式 @import
、以及 CSS 的 @import url(...)
。含示例、对比表、迁移步骤与避坑清单。
@import "xxx"
:Sass 旧式导入(已弃用)
作用
编译期 把被导入的 SCSS 内容"直接拼接"到当前位置,变量/混入进入全局 ,容易重复加载、顺序踩坑。Dart Sass 已弃用 ,推荐使用@use/@forward
。
示例
scss
@import "./tokens"; // 编译时把 tokens.scss 的内容贴进来(非 CSS 运行时)
@import url(...)
:CSS 的导入
作用
浏览器在运行时 请求外部 CSS 文件;不会引入 Sass 的变量/混入/函数。
示例
arduino
@import url("/base.css"); /* 或者 @import "/print.css" print */
位置限制
必须在样式表最前面 (在任何普通规则前;前面最多有 @charset
/ 其它 @import
)。影响性能,一般不建议使用。
@use
:模块化导入(推荐)
作用
将另一个 SCSS 文件当作"模块"加载,默认通过命名空间 访问变量/函数/混入;只加载一次、不污染全局,避免命名冲突。
示例
less
/* tokens/_color.scss */
$primary: #0b81ff !default;
@mixin btn { padding: 8px 12px; border-radius: 8px; }
/* app.scss */
@use "./tokens/color" as c; // 起别名 c
.button {
color: c.$primary;
@include c.btn();
}
配置默认变量(with + !default)
less
@use "./tokens/color" as c with (
$primary: #0052d9 // 仅能配置标了 !default 的顶层公开变量
);
要点
- 命名空间:
@use "x" as x;
或 不建议 的as *
(去掉前缀,易冲突)。 - 变量只读:
c.$primary
不能在引入方直接赋值,只能用with
在加载时配置。
@forward
:聚合/转发导出
作用
把若干模块"转发 "出去,做一个统一出口 (barrel/index)。自己文件里不能直接使用 转发来的成员;若要自用,再 @use
一次。
示例
less
/* design/_index.scss ------ 聚合出口 */
@forward "../tokens/color" show $primary, btn; // 只暴露想给外部用的成员
@forward "../tokens/spacing" as space-*; // 导出时加前缀
/* app.scss ------ 使用统一出口 */
@use "./design/index" as d;
.card {
color: d.$primary;
margin: d.$space-lg;
}
在出口处预配置主题(with)
less
/* design/_index.scss */
@forward "../tokens/color" with ($primary: #333);
注意:一个模块只能被配置一次 。上游已通过
@forward ... with
配过,下游再配会报错。
五分钟速查表
能力/特性 | @use |
@forward |
Sass @import "x" |
CSS @import url(...) |
---|---|---|---|---|
发生时机 | 编译期 | 编译期 | 编译期 | 运行时(浏览器请求) |
命名空间 | 有(可 as * 去掉) |
对外导出,不给本文件用 | 无(全局拼接) | 无 |
去重加载 | ✅ | ✅ | ❌ 可能重复 | N/A(浏览器请求) |
变量可配置 | 通过 with 配置 !default |
通过 with 预配置并转发 |
通过"先定义后导入"覆盖(老做法) | ❌ |
全局污染 | ❌ | ❌ | ✅ | ❌ |
位置限制 | 任意 | 任意 | 任意(编译期) | 顶部(在普通规则前) |
适用场景 | 模块化使用 | 统一出口/SDK | 旧项目遗留 | 引入纯 CSS(不推荐) |
常见误区 & 快速排坑
-
@import url('./variable.scss')
用后$color
未定义- 这是 CSS 导入,不会带来 Sass 变量。
- 用:
@use "./variable" as v;
→color: v.$color;
-
我在文件里写
$primary: red
,为啥@use
来的变量没变?@use
是模块隔离;你改的是当前文件 的$primary
,不是模块里的。- 正确:
@use "./tokens" with ($primary: red);
且源变量需!default
。
-
去命名空间
as *
和@import
一样吗?- 不是。
as *
只是省掉前缀,仍是模块系统(只加载一次、不污染全局)。 - 但有冲突风险:多个模块导出同名变量会报错。
- 不是。
-
@forward
文件里用不了转发来的变量?- 对。
@forward
只是出口;若当前文件要用,再@use
一次。
- 对。
-
位置问题:为啥我的
@import
被忽略?- CSS 的
@import
必须在最顶部 (普通规则之前)。Sass 旧式@import
不限位置,但已经弃用。
- CSS 的
迁移指北:从 @import
到 @use/@forward
目录建议
arduino
styles/
tokens/
_color.scss // 变量均加 !default
_spacing.scss
mixins/
_typography.scss
design/
_index.scss // 聚合出口(只 forward)
app.scss // 项目入口(只 use design)
改造步骤
-
给需要对外可配的变量都加
!default
。 -
建"总出口":
less/* design/_index.scss */ @forward "../tokens/color"; @forward "../tokens/spacing"; @forward "../mixins/typography";
-
入口使用:
css/* app.scss */ @use "./design/index" as d with ( $primary: #0052d9, $space-lg: 24px ); .btn { color: d.$primary; margin: d.$space-lg; }
-
删除旧式
@import
,逐步把业务文件改为@use
指向design/_index.scss
。
结语
- 新项目:只用
@use
+@forward
。 - 做 SDK/设计系统:
@forward
聚合成一个总入口 ,外部只@use
它。 - 变量可配:源头加
!default
,引入处用with
。 - 避免
@import
与 CSS 的@import url(...)
(性能差、易踩坑)。
需要我按你的项目目录,直接给一份可跑的 @use/@forward
模板吗?把目录贴过来我就给你落地版。