Lzh on GitHub

@use

@use 规则从其他 Sass 样式表加载 混合宏、函数 和 变量,并将多个样式表中的 CSS 组合在一起。通过 @use 加载的样式表称为 “模块”。Sass 还提供了充满有用函数的内置模块。

@use 规则从其他 Sass 样式表加载 混合宏函数变量,并将多个样式表中的 CSS 组合在一起。通过 @use 加载的样式表称为 “模块”。Sass 还提供了充满有用函数内置模块

最简单的 @use 规则是 @use "",它加载给定 URL 的模块。以这种方式加载的任何样式都将只在编译后的 CSS 输出中包含一次,无论这些样式被加载多少次。

样式表的 @use 规则必须在除 @forward 之外的任何其他规则之前,包括样式规则。但是,你可以在 @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';

加载成员

你可以通过编写 <命名空间>.<变量><命名空间>.<函数>()@include <命名空间>.<混合宏>() 来访问另一个模块中的变量、函数和混合宏。默认情况下,命名空间就是模块 URL 的最后一个组件。

使用 @use 加载的成员(变量、函数和混合宏)只在加载它们的样式表中可见。其他样式表如果也想访问它们,需要编写自己的 @use 规则。这有助于轻松地确定每个成员的确切来源。如果你想一次从多个文件加载成员,可以使用 @forward 规则将它们全部从一个共享文件中转发出去。

由于 @use 为成员名添加了命名空间,因此在编写样式表时,可以安全地选择非常简单的名称,如 $radius$width。这与旧的 @import 规则不同,后者鼓励用户编写像 $mat-corner-radius 这样长的名称,以避免与其他库发生冲突,这有助于保持你的样式表清晰易读!
// src/_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}

// style.scss
@use "src/corners";

.button {
  @include corners.rounded;
  padding: 5px + corners.$radius;
}

选择命名空间

默认情况下,模块的命名空间只是其 URL 的最后一个组件,不带文件扩展名。然而,有时你可能想选择一个不同的命名空间——你可能想为一个经常引用的模块使用更短的名称,或者你可能正在加载多个具有相同文件名的模块。你可以通过编写 @use "" as <命名空间> 来实现。

// 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;
}

你甚至可以通过编写 @use "" as *** 来 ** 不 使用命名空间加载模块。但是,我们建议你只对你自己编写的样式表这样做;否则,它们可能会引入导致名称冲突的新成员!

// src/_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}

// style.scss
@use "src/corners" as *;

.button {
  @include rounded;
  padding: 5px + $radius;
}

私有成员

作为样式表作者,你可能不希望你定义的所有成员都在样式表之外可用。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;
}

配置

样式表可以使用 !default 标志 定义变量,使其可配置。要加载带有配置的模块,请编写 @use with (<变量>: <值>, <变量>: <值>)。配置的值将覆盖变量的默认值。

// _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
);

即使一个模块被多次加载,它也会保持相同的配置(或缺乏配置)。因此,@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.

使用混合宏

使用 @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.scss
$color: red;

// _override.scss
@use 'library';
library.$color: blue;

// style.scss
@use 'library';
@use 'override';
@debug library.$color;  //=> blue

即使你使用 ** as * ** 加载一个没有命名空间的模块,这也有效。给在该模块中定义的变量名赋值将覆盖其在该模块中的值。

内置模块变量(例如 math.$pi)不能重新赋值。

查找模块

为要加载的每个样式表写出绝对 URL 并非易事,因此 Sass 的模块查找算法使其变得更容易。首先,你无需显式写出要加载的文件的扩展名;@use "variables" 将自动加载 variables.scssvariables.sassvariables.css

为了确保样式表在每个操作系统上都能正常工作,Sass 通过 URL 加载文件,而不是文件路径。这意味着你必须使用正斜杠,而不是反斜杠,即使在 Windows 上也是如此。这也意味着 URL 是区分大小写的,因此 Sass 会将 Styles.scssstyles.scss 视为不同的模块,即使你使用的是不区分大小写的文件系统。请确保你的 URL 与磁盘上文件的实际大小写匹配,否则你的样式表可能会加载两次,并且肯定无法在其他操作系统上运行。

加载路径

所有 Sass 实现都允许用户提供加载路径:Sass 在定位模块时会查找的文件系统路径。例如,如果你将 node_modules/susy/sass 作为加载路径传递,你可以使用 @use "susy" 来加载 node_modules/susy/sass/susy.scss(尽管 pkg: URL 是一种更好的处理方式)。

但是,模块将始终首先相对于当前文件加载。只有在没有匹配模块 URL 的相对文件存在时,才会使用加载路径。这确保了你在添加新库时不会意外地弄乱你的相对导入。

与某些其他语言不同,Sass 不需要你为相对导入使用 ./。相对导入总是可用的。

局部文件

按照惯例,只打算作为模块加载而不单独编译的 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';

pkg: URL

Sass 使用 pkg: URL 方案来加载由各种包管理器分发的样式表。由于 Sass 在许多具有不同包管理约定的编程语言环境中使用,pkg: URL 几乎没有固定的含义。相反,我们鼓励用户实现自定义导入器(使用 JS APIEmbedded Sass 协议)来使用本机包管理器的逻辑解析这些 URL。

这使得 pkg: URL 和使用它们的样式表可以在不同的语言生态系统中移植。无论你是通过 npm 安装 Sass 库(Sass 为此提供了一个内置的 pkg: 导入器),还是找到的最不起眼的包管理器,如果你编写 @use 'pkg:library',它都会做正确的事情。

pkg: URL 不仅仅用于 @use。你可以在任何可以加载 Sass 文件的地方使用它们,包括 @forwardmeta.load-css(),甚至旧的 @import 规则。

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';

作为模块加载的 CSS 文件不允许任何特殊的 Sass 功能,因此不能公开任何 Sass 变量、函数或混合宏。为了确保作者不会在他们的 CSS 中意外编写 Sass,所有无效的 Sass 功能都会产生错误。否则,CSS 将按原样呈现。它甚至可以被扩展

与 @import 的区别

@use 规则旨在取代旧的 @import 规则,但它被有意设计为工作方式不同。以下是两者之间的一些主要区别:

  • @use 只在当前文件的作用域内使变量、函数和混合宏可用。它永远不会将它们添加到全局作用域。这使得你可以轻松地确定 Sass 文件引用的每个名称来自哪里,并且意味着你可以使用更短的名称而不会有任何冲突风险。
  • @use 只会加载每个文件一次。这确保你不会意外地多次重复你的依赖项的 CSS。
  • @use 必须出现在文件的开头,并且不能嵌套在样式规则中。嵌套的导入可以迁移到混合宏调用meta.load-css()
  • 每个 @use 规则只能有一个 URL。
  • @use 要求其 URL 必须有引号,即使在使用缩进语法时也是如此。