配合 @use 使用的规则

因为 @use 引入的模块只能在当前文件内使用,所以说如果要组合多个模块作为一个新模块暴露出去,是行不通的

@forward 正是为此而生

@forward 会加载 Sass 样式表,并让其混入(mixin)函数(function)变量在当别的样式表使用 @use 引入当前样式表时能够被使用。它使跨多个文件组织 Sass 库成为可能,用户可以加载单个入口文件。

基本使用

基础语法为 @forward "<url>"。它与 @use 一样通过 URL 来加载模块,但它让使用该模块的用户能够使用已加模块的公共成员,就像这些已加载模块的公共成员定义在了该模块内一样。

@forward 引入的模块在当前文件中是不可用的(仅仅是字面意思的转发),如果需要使用,还需要编写 @use 规则。不用担心,它只会被加载一次!

如果同时使用 @forward@use 引入一个文件,先写 @forward 总是没错的。这样的话,用户就可以被转发的模块;反之,如果先写 @use,用户就不能配置被转发的模块(会报错)。

在处理模块中的 CSS 样式时,@forward@use 并无差别。来自被转发模块的样式会包含在输出的 CSS 中,并且在只有 @forward 的却无 @use 模块中,被转发模块的样式可以被继承(@extend)。

1
2
3
4
5
6
// src/_list.scss
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
1
2
// bootstrap.scss
@forward 'src/list';
1
2
3
4
5
6
// styles.scss
@use 'bootstrap';

li {
@include bootstrap.list-reset;
}
1
2
3
4
5
li {
margin: 0;
padding: 0;
list-style: none;
}

添加前缀

在模块中的成员,因为有了命名空间这一特性,通常名称都非常简单易懂。但是这些名称在其模块外部可能并无意义,所以 @forward 能够在转发的模块前加上额外的前缀。

格式为 @forward "<url>" as <prefix>-*,它会在每个混入(mixin)、函数(function)和变量的名称前加上前缀。例如在某个模块中有一个成员叫 reset,它被转发后 as list-*,那么在外部需通过 list-reset 来使用。

1
2
3
4
5
6
// src/_list.scss
@mixin reset {
margin: 0;
padding: 0;
list-style: none;
}
1
2
// bootstrap.scss
@forward 'src/list' as list-*;
1
2
3
4
5
6
// styles.scss
@use 'bootstrap';

li {
@include bootstrap.list-reset;
}
1
2
3
4
5
li {
margin: 0;
padding: 0;
list-style: none;
}

可见性

有时候你不希望转发模块中所有成员。你希望有些成员变量是私有的,只在你的包内才能使用;又或者你希望用户用不同的方法加载某些成员。你可以通过 @forward "<url>" hide <members...> 或者 @forward "<url>" show <members...> 来精准控制哪些成员能够转发。

hide 隐藏意味着不应该转发列表中的成员,其余成员都应正常转发。show 意味着只转发列表中指定的成员。在列表中可以列出混入(mixin)、函数(function)和变量(要带上$)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/_list.scss
$horizontal-list-gap: 2em;

@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}

@mixin list-horizontal {
@include list-reset;

li {
display: inline-block;
margin: {
left: -2px;
right: $horizontal-list-gap;
}
}
}
1
2
// bootstrap.scss
@forward 'src/list' hide list-reset, $horizontal-list-gap;

配置模块

@use 的配置方法几乎一致,唯一区别是 @forward 配置中的值可以使用 flag !default。这样在允许模块修改上游值的同时,下游也能覆盖该默认值。

1
2
3
4
5
6
7
8
9
// _library.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;

code {
border-radius: $border-radius;
box-shadow: $box-shadow;
}
1
2
3
4
5
// _opinionated.scss
@forward 'library' with (
$black: #222 !default, // 覆盖了 library 的值
$border-radius: 0.1rem !default
);
1
2
3
4
// style.scss
@use 'opinionated' with (
$black: #333 // 覆盖了 opinionated 的值
);
1
2
3
4
code {
border-radius: 0.1rem;
box-shadow: 0 0.5rem 1rem rgba(51, 51, 51, 0.15);
}