@use
@use 规则从其他 Sass 样式表加载 混合宏、函数 和 变量,并将多个样式表中的 CSS 组合在一起。通过 @use 加载的样式表称为 “模块”。Sass 还提供了充满有用函数的内置模块。
最简单的 @use 规则是 @use "
// foundation/_code.scss
code {
padding: .25em;
line-height: 0;
}
// foundation/_lists.scss
ul, ol {
text-align: left;
& & {
padding: {
bottom: 0;
left: 0;
}
}
}
// style.scss
@use 'foundation/code';
@use 'foundation/lists';
// foundation/_code.sass
code
padding: .25em
line-height: 0
// foundation/_lists.sass
ul, ol
text-align: left
& &
padding:
bottom: 0
left: 0
// style.sass
@use 'foundation/code'
@use 'foundation/lists'
code {
padding: .25em;
line-height: 0;
}
ul, ol {
text-align: left;
}
ul ul, ol ol {
padding-bottom: 0;
padding-left: 0;
}
加载成员
你可以通过编写 <命名空间>.<变量>、<命名空间>.<函数>() 或 @include <命名空间>.<混合宏>() 来访问另一个模块中的变量、函数和混合宏。默认情况下,命名空间就是模块 URL 的最后一个组件。
使用 @use 加载的成员(变量、函数和混合宏)只在加载它们的样式表中可见。其他样式表如果也想访问它们,需要编写自己的 @use 规则。这有助于轻松地确定每个成员的确切来源。如果你想一次从多个文件加载成员,可以使用 @forward 规则将它们全部从一个共享文件中转发出去。
// src/_corners.scss
$radius: 3px;
@mixin rounded {
border-radius: $radius;
}
// style.scss
@use "src/corners";
.button {
@include corners.rounded;
padding: 5px + corners.$radius;
}
// src/_corners.sass
$radius: 3px
@mixin rounded
border-radius: $radius
// style.sass
@use "src/corners"
.button
@include corners.rounded
padding: 5px + corners.$radius
.button {
border-radius: 3px;
padding: 8px;
}
选择命名空间
默认情况下,模块的命名空间只是其 URL 的最后一个组件,不带文件扩展名。然而,有时你可能想选择一个不同的命名空间——你可能想为一个经常引用的模块使用更短的名称,或者你可能正在加载多个具有相同文件名的模块。你可以通过编写 @use "
// src/_corners.scss
$radius: 3px;
@mixin rounded {
border-radius: $radius;
}
// style.scss
@use "src/corners" as c;
.button {
@include c.rounded;
padding: 5px + c.$radius;
}
// src/_corners.sass
$radius: 3px
@mixin rounded
border-radius: $radius
// style.sass
@use "src/corners" as c
.button
@include c.rounded
padding: 5px + c.$radius
.button {
border-radius: 3px;
padding: 8px;
}
你甚至可以通过编写 @use "
// src/_corners.scss
$radius: 3px;
@mixin rounded {
border-radius: $radius;
}
// style.scss
@use "src/corners" as *;
.button {
@include rounded;
padding: 5px + $radius;
}
// src/_corners.sass
$radius: 3px
@mixin rounded
border-radius: $radius
// style.sass
@use "src/corners" as *
.button
@include rounded
padding: 5px + $radius
.button {
border-radius: 3px;
padding: 8px;
}
私有成员
作为样式表作者,你可能不希望你定义的所有成员都在样式表之外可用。Sass 通过让成员名以 - 或 _ 开头来轻松定义私有成员。这些成员在定义它们的样式表内部会像正常成员一样工作,但它们不会成为模块公共 API 的一部分。这意味着加载你的模块的样式表无法看到它们!
// src/_corners.scss
$-radius: 3px;
@mixin rounded {
border-radius: $-radius;
}
// style.scss
@use "src/corners";
.button {
@include corners.rounded;
// This is an error! $-radius isn't visible outside of `_corners.scss`.
padding: 5px + corners.$-radius;
}
// src/_corners.sass
$-radius: 3px
@mixin rounded
border-radius: $-radius
// style.sass
@use "src/corners"
.button
@include corners.rounded
// This is an error! $-radius isn't visible outside of `_corners.scss`.
padding: 5px + corners.$-radius
配置
样式表可以使用 !default 标志 定义变量,使其可配置。要加载带有配置的模块,请编写 @use
// _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;
}
// style.scss
@use 'library' with (
$black: #222,
$border-radius: 0.1rem
);
// _library.sass
$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
// style.sass
@use 'library' with ($black: #222, $border-radius: 0.1rem)
code {
border-radius: 0.1rem;
box-shadow: 0 0.5rem 1rem rgba(34, 34, 34, 0.15);
}
即使一个模块被多次加载,它也会保持相同的配置(或缺乏配置)。因此,@use ... with 只能在每个模块第一次加载时使用一次。这也使得使用配置来创建在整个编译过程中应用的 “主题” 成为可能:
// components/_button.scss
@use "../theme";
button {
color: theme.$text-color;
background-color: theme.$background-color;
}
// _theme.scss
$text-color: black !default;
$background-color: white !default;
// dark.scss
@use "theme" with (
$text-color: white,
$background-color: black,
);
@use "components/button";
// More components are usually imported here.
// components/_button.scss
@use "../theme"
button
color: theme.$text-color
background-color: theme.$background-color
// _theme.scss
$text-color: black !default
$background-color: white !default
// dark.scss
@use "theme" with (
$text-color: white,
$background-color: black,
)
@use "components/button"
// More components are usually imported here.
button {
color: white;
background-color: black;
}
使用混合宏
使用 @use ... with 配置模块非常方便,尤其是在使用最初为 @import 规则编写的库时。但它并不特别灵活,我们不建议将其用于更高级的用例。如果你发现自己想一次配置多个变量、将映射作为配置传递或在模块加载后更新配置,请考虑编写一个混合宏来设置你的变量,并编写另一个混合宏来注入你的样式。
// _library.scss
$-black: #000;
$-border-radius: 0.25rem;
$-box-shadow: null;
/// If the user has configured `$-box-shadow`, returns their configured value.
/// Otherwise returns a value derived from `$-black`.
@function -box-shadow() {
@return $-box-shadow or (0 0.5rem 1rem rgba($-black, 0.15));
}
@mixin configure($black: null, $border-radius: null, $box-shadow: null) {
@if $black {
$-black: $black !global;
}
@if $border-radius {
$-border-radius: $border-radius !global;
}
@if $box-shadow {
$-box-shadow: $box-shadow !global;
}
}
@mixin styles {
code {
border-radius: $-border-radius;
box-shadow: -box-shadow();
}
}
// style.scss
@use 'library';
@include library.configure(
$black: #222,
$border-radius: 0.1rem
);
@include library.styles;
// _library.sass
$-black: #000
$-border-radius: 0.25rem
$-box-shadow: null
/// If the user has configured `$-box-shadow`, returns their configured value.
/// Otherwise returns a value derived from `$-black`.
@function -box-shadow()
@return $-box-shadow or (0 0.5rem 1rem rgba($-black, 0.15))
@mixin configure($black: null, $border-radius: null, $box-shadow: null)
@if $black
$-black: $black !global
@if $border-radius
$-border-radius: $border-radius !global
@if $box-shadow
$-box-shadow: $box-shadow !global
@mixin styles
code
border-radius: $-border-radius
box-shadow: -box-shadow()
code {
border-radius: 0.1rem;
box-shadow: 0 0.5rem 1rem rgba(34, 34, 34, 0.15);
}
重新赋值变量
加载模块后,你可以重新赋值它的变量。
// _library.scss
$color: red;
// _override.scss
@use 'library';
library.$color: blue;
// style.scss
@use 'library';
@use 'override';
@debug library.$color; //=> blue
// _library.sass
$color: red
// _override.sass
@use 'library'
library.$color: blue
// style.sass
@use 'library'
@use 'override'
@debug library.$color //=> blue
即使你使用 ** as * ** 加载一个没有命名空间的模块,这也有效。给在该模块中定义的变量名赋值将覆盖其在该模块中的值。
math.$pi)不能重新赋值。查找模块
为要加载的每个样式表写出绝对 URL 并非易事,因此 Sass 的模块查找算法使其变得更容易。首先,你无需显式写出要加载的文件的扩展名;@use "variables" 将自动加载 variables.scss、variables.sass 或 variables.css。
加载路径
所有 Sass 实现都允许用户提供加载路径:Sass 在定位模块时会查找的文件系统路径。例如,如果你将 node_modules/susy/sass 作为加载路径传递,你可以使用 @use "susy" 来加载 node_modules/susy/sass/susy.scss(尽管 pkg: URL 是一种更好的处理方式)。
但是,模块将始终首先相对于当前文件加载。只有在没有匹配模块 URL 的相对文件存在时,才会使用加载路径。这确保了你在添加新库时不会意外地弄乱你的相对导入。
局部文件
按照惯例,只打算作为模块加载而不单独编译的 Sass 文件以 _ 开头(如 _code.scss)。这些被称为局部文件,它们告诉 Sass 工具不要尝试单独编译这些文件。在导入局部文件时,你可以省略 _。
索引文件
如果你在一个文件夹中编写了 _index.scss 或 _index.sass,当加载该文件夹本身的 URL 时,该索引文件将自动加载。
// foundation/_code.scss
code {
padding: .25em;
line-height: 0;
}
// foundation/_lists.scss
ul, ol {
text-align: left;
& & {
padding: {
bottom: 0;
left: 0;
}
}
}
// foundation/_index.scss
@use 'code';
@use 'lists';
// style.scss
@use 'foundation';
// foundation/_code.sass
code
padding: .25em
line-height: 0
// foundation/_lists.sass
ul, ol
text-align: left
& &
padding:
bottom: 0
left: 0
// foundation/_index.sass
@use 'code'
@use 'lists'
// style.sass
@use 'foundation'
code {
padding: .25em;
line-height: 0;
}
ul, ol {
text-align: left;
}
ul ul, ol ol {
padding-bottom: 0;
padding-left: 0;
}
pkg: URL
Sass 使用 pkg: URL 方案来加载由各种包管理器分发的样式表。由于 Sass 在许多具有不同包管理约定的编程语言环境中使用,pkg: URL 几乎没有固定的含义。相反,我们鼓励用户实现自定义导入器(使用 JS API 或 Embedded Sass 协议)来使用本机包管理器的逻辑解析这些 URL。
这使得 pkg: URL 和使用它们的样式表可以在不同的语言生态系统中移植。无论你是通过 npm 安装 Sass 库(Sass 为此提供了一个内置的 pkg: 导入器),还是找到的最不起眼的包管理器,如果你编写 @use 'pkg:library',它都会做正确的事情。
pkg: 导入器的规则
Sass 希望所有 pkg: 导入器都遵循一些通用规则。这些规则有助于确保 pkg: URL 在所有包管理器中得到一致处理,从而使样式表尽可能可移植。
除了自定义导入器的标准规则外,pkg: 导入器必须只处理非规范的 URL,这些 URL:
- 具有方案 pkg,并且
- 其路径以包名开头,并且
- 可选地,后面跟着一个路径,路径段用正斜杠分隔。
- 包名可能包含正斜杠,这取决于特定的包管理器是否支持。例如,npm 允许像 @namespace/name 这样的包名。请注意,包含非字母数字字符的包名在不同的包管理器之间可能可移植性较差。
pkg: 导入器必须拒绝以下模式:
- 路径以 / 开头的 URL。
- 具有非空/空用户名、密码、主机、端口、查询或片段的 URL。
如果 pkg: 导入器遇到违反其自身包管理器约定但 不 违反上述规则的 URL,它应该只是拒绝加载该 URL,而不是抛出错误。这使得用户可以在必要时一次使用多个 pkg: 导入器。
Node.js 包导入器
由于 Sass 在 Node.js 生态系统中应用最广泛,因此它带有一个 pkg: 导入器,该导入器使用与 Node.js 相同的算法来加载 Sass 样式表。这默认情况下不可用,但很容易开启:
- 如果你使用 JavaScript API,只需将 new NodePackageImporter() 添加到 importers 选项中。
- 如果你使用 Dart API,将 NodePackageImporter() 添加到 importers 选项中。
- 如果你使用命令行,传入 --pkg-importer=node。
如果你加载一个 pkg: URL,Node.js pkg: 导入器将查看其 package.json 文件以确定要加载哪个 Sass 文件。它将按以下顺序检查:
- "exports" 字段,条件为 "sass"、"style" 和 "default"。这是包在未来公开 Sass 入口点的推荐方式。
- "sass" 字段或 "style" 字段,它应该是一个 Sass 文件的路径。这仅在 pkg: URL 没有子路径时有效——pkg:library 将加载 "sass" 字段中列出的文件,但 pkg:library/button 将从包的根目录加载 button.scss。
- 包根目录下的索引文件。这也仅在 pkg: URL 没有子路径时有效。
Node.js pkg: 导入器支持完整的 "exports" 功能,因此你也可以为不同的子路径指定不同的位置(请注意,键必须包含文件扩展名):
{
"exports": {
".": {
"sass": "styles/index.scss",
},
"./button.scss": {
"sass": "styles/button.scss",
},
"./accordion.scss": {
"sass": "styles/accordion.scss",
}
}
}
...甚至模式:
{
"exports": {
".": {
"sass": "styles/index.scss",
},
"./*.scss": {
"sass": "styles/*.scss",
},
}
}
加载 CSS
除了加载 .sass 和 .scss 文件,Sass 还可以加载普通的 .css 文件。
// code.css
code {
padding: .25em;
line-height: 0;
}
// style.scss
@use 'code';
// code.css
code
padding: .25em
line-height: 0
// style.sass
@use 'code'
code {
padding: .25em;
line-height: 0;
}
作为模块加载的 CSS 文件不允许任何特殊的 Sass 功能,因此不能公开任何 Sass 变量、函数或混合宏。为了确保作者不会在他们的 CSS 中意外编写 Sass,所有无效的 Sass 功能都会产生错误。否则,CSS 将按原样呈现。它甚至可以被扩展!
与 @import 的区别
@use 规则旨在取代旧的 @import 规则,但它被有意设计为工作方式不同。以下是两者之间的一些主要区别:
- @use 只在当前文件的作用域内使变量、函数和混合宏可用。它永远不会将它们添加到全局作用域。这使得你可以轻松地确定 Sass 文件引用的每个名称来自哪里,并且意味着你可以使用更短的名称而不会有任何冲突风险。
- @use 只会加载每个文件一次。这确保你不会意外地多次重复你的依赖项的 CSS。
- @use 必须出现在文件的开头,并且不能嵌套在样式规则中。嵌套的导入可以迁移到混合宏调用或 meta.load-css()。
- 每个 @use 规则只能有一个 URL。
- @use 要求其 URL 必须有引号,即使在使用缩进语法时也是如此。