Lzh on GitHub

@import

Sass 扩展了 CSS 的 @import 规则,使其能够导入 Sass 和 CSS 样式表,提供对混合宏、函数和变量的访问,并将多个样式表的 CSS 组合在一起。与普通的 CSS 导入不同,后者要求浏览器在渲染页面时进行多次 HTTP 请求,而 Sass 导入则完全在编译期间处理。

Sass 扩展了 CSS 的 @import 规则,使其能够导入 Sass 和 CSS 样式表,提供对混合宏函数变量的访问,并将多个样式表的 CSS 组合在一起。与普通的 CSS 导入不同,后者要求浏览器在渲染页面时进行多次 HTTP 请求,而 Sass 导入则完全在编译期间处理。

Sass 导入的语法与 CSS 导入相同,只是它们允许多个导入之间用逗号分隔,而不是要求每个导入都有自己的 @import。此外,在缩进语法中,导入的 URL 不需要有引号。

自 Dart Sass 1.80.0 版本起,@import 规则已弃用,并将在 Dart Sass 3.0.0 中从语言中移除。请优先使用 @use 规则@import 有什么问题?@import 规则存在一些严重问题:
  • @import 使所有变量、混合宏和函数都全局可访问。这使得人们(或工具)很难分辨任何东西是在哪里定义的。
  • 因为所有东西都是全局的,库必须给所有成员添加前缀以避免命名冲突。
  • @extend 规则也是全局的,这使得预测哪些样式规则将被扩展变得困难。
  • 每个样式表在每次被 @imported 时都会被执行并发出其 CSS,这增加了编译时间并产生臃肿的输出。
  • 无法定义私有成员或占位符选择器,使其对下游样式表不可访问。
新的模块系统@use 规则解决了所有这些问题。我如何迁移?我们编写了一个迁移工具,可以自动将大多数基于 @import 的代码快速转换为基于 @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
@import 'foundation/code', 'foundation/lists';

当 Sass 导入一个文件时,该文件被评估,就像它的内容直接出现在 @import 的位置一样。来自导入文件的任何混合宏函数变量都变得可用,并且其所有 CSS 都包含在 @import 编写的确切位置。此外,在 @import 之前定义的任何混合宏、函数或变量(包括来自其他 @imports 的)在导入的样式表中都可用。

如果同一个样式表被导入多次,它每次都会被再次评估。如果它只定义了函数和混合宏,这通常不是什么大问题,但如果它包含样式规则,它们将被编译成 CSS 多次。

查找文件

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

为了确保样式表在每个操作系统上都能正常工作,Sass 通过 URL 导入文件,而不是文件路径。这意味着你必须使用正斜杠,而不是反斜杠,即使在 Windows 上也是如此。

加载路径

所有 Sass 实现都允许用户提供加载路径:Sass 在解析导入时会查找的文件系统路径。例如,如果你将 node_modules/susy/sass 作为加载路径传递,你可以使用 @import "susy" 来加载 node_modules/susy/sass/susy.scss

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

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

局部文件

按照惯例,只打算作为导入而不单独编译的 Sass 文件以 _ 开头(如 _code.scss)。这些被称为局部文件,它们告诉 Sass 工具不要尝试单独编译这些文件。在导入局部文件时,你可以省略 _

索引文件

如果你在一个文件夹中编写了 _index.scss_index.sass,当文件夹本身被导入时,该文件将加载。

// 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
@import 'code', 'lists';

// style.scss
@import 'foundation';

自定义导入器

所有 Sass 实现都提供了一种定义自定义导入器的方法,它控制 @imports 如何定位样式表:

  • Node Sass 和 npm 上的 Dart Sass 提供了一个 importer 选项作为其 JS API 的一部分。
  • pub 上的 Dart Sass 提供了一个抽象的 Importer 类,可以由自定义导入器扩展。
  • Ruby Sass 提供了一个抽象的 Importers::Base 类,可以由自定义导入器扩展。

嵌套

导入通常写在样式表的顶层,但并非必须如此。它们也可以嵌套在样式规则普通 CSS at-rules 中。导入的 CSS 在该上下文中嵌套,这使得嵌套导入对于将一块 CSS 作用域限定到特定元素或媒体查询非常有用。在嵌套导入中定义的顶层混合宏函数变量仅在嵌套上下文中可用。

// _theme.scss
pre, code {
  font-family: 'Source Code Pro', Helvetica, Arial;
  border-radius: 4px;
}

// style.scss
.theme-sample {
  @import "theme";
}
嵌套导入对于作用域第三方样式表非常有用,但如果你是你正在导入的样式表的作者,通常更好的做法是将你的样式写在一个混合宏中,并将该混合宏包含在嵌套上下文中。混合宏可以以更灵活的方式使用,并且在查看导入的样式表时,它的预期用途更清晰。
嵌套导入中的 CSS 像混合宏一样被评估,这意味着任何父选择器都将引用样式表嵌套在其中的选择器。
// _theme.scss
ul li {
  $padding: 16px;
  padding-left: $padding;
  [dir=rtl] & {
    padding: {
      left: 0;
      right: $padding;
    }
  }
}

// style.scss
.theme-sample {
  @import "theme";
}

导入 CSS

除了导入 .sass.scss 文件,Sass 还可以导入普通的 .css 文件。唯一的规则是导入不能显式包含 .css 扩展名,因为这用于指示一个普通 CSS @import

// code.css
code {
  padding: .25em;
  line-height: 0;
}

// style.scss
@import 'code';

由 Sass 导入的 CSS 文件不允许任何特殊的 Sass 功能。为了确保作者不会在他们的 CSS 中意外编写 Sass,所有无效的 Sass 功能都会产生错误。否则,CSS 将按原样呈现。它甚至可以被扩展

普通 CSS @imports

因为 @import 也在 CSS 中定义,Sass 需要一种方法来编译普通的 CSS @imports,而不必在编译时尝试导入文件。为了实现这一点,并确保 SCSS 尽可能成为 CSS 的超集,Sass 会将具有以下特征的 @imports 编译为普通的 CSS 导入:

  • URL 以 .css 结尾的导入。
  • URL 以 http://https:// 开头的导入。
  • URL 写为 url() 的导入。
  • 具有媒体查询的导入。
@import "theme.css";
@import "http://fonts.googleapis.com/css?family=Droid+Sans";
@import url(theme);
@import "landscape" screen and (orientation: landscape);

插值

虽然 Sass 导入不能使用插值(以确保始终可以分辨出混合宏函数变量来自哪里),但普通的 CSS 导入可以。这使得动态生成导入成为可能,例如基于混合宏参数。

@mixin google-font($family) {
  @import url("http://fonts.googleapis.com/css?family=#{$family}");
}

@include google-font("Droid Sans");

导入和模块

Sass 的模块系统@import 无缝集成,无论你是导入一个包含 @use 规则的文件,还是将一个包含导入的文件作为模块加载。我们希望让从 @import@use 的过渡尽可能平滑。

导入模块系统文件

当你导入一个包含 @use 规则的文件时,导入文件可以访问直接在该文件中定义的所有成员(甚至包括私有成员),但能访问来自该文件已加载的模块中的任何成员。但是,如果该文件包含 @forward 规则,导入文件将可以访问被转发的成员。这意味着你可以导入一个为与模块系统一起使用而编写的库。

当一个包含 @use 规则的文件被导入时,这些规则传递性地加载的所有 CSS 都包含在结果样式表中,即使它已经被另一个导入包含在内。如果你不小心,这可能会导致臃肿的 CSS 输出!

仅导入文件

对于 @use 有意义的 API 可能对 @import 没有意义。例如,@use 默认会给所有成员添加命名空间,因此你可以安全地使用短名称,而 @import 则不会,所以你可能需要更长的名称。如果你是库作者,你可能会担心,如果你更新你的库以使用新的模块系统,你现有的基于 @import 的用户会崩溃。

为了使这更容易,Sass 还支持仅导入文件。如果你将一个文件命名为 <name>.import.scss,它将只用于导入,而不用于 @uses。这样,你可以在保留对 @import 用户的兼容性的同时,为新模块系统的用户提供一个优秀的 API。

// _reset.scss

// Module system users write `@include reset.list()`.
@mixin list() {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }
}

// _reset.import.scss

// Legacy import users can keep writing `@include reset-list()`.
@forward "reset" as reset-*;

通过导入配置模块

你可以通过在第一次加载该模块的 @import 之前定义全局变量来配置通过 @import 加载的模块。

// _library.scss
$color: blue !default;

a {
  color: $color;
}

// _library.import.scss
@forward 'library' as lib-*;

// style.sass
$lib-color: green;
@import "library";
模块只加载一次,所以如果你在第一次 @import 一个模块后(即使是间接的)更改了配置,如果你再次 @import 该模块,更改将被忽略。

加载包含导入的模块

当你使用 @use(或 @forward)加载一个使用 @import 的模块时,该模块将包含你加载的样式表直接定义的所有公共成员以及该样式表传递性导入的所有内容。换句话说,所有被导入的内容都被视为在一个大的样式表中编写的。

这使得即使在你依赖的所有库都转换为新的模块系统之前,也很容易开始在样式表中使用 @use。但是,请注意,如果它们确实转换了,它们的 API 很可能会改变!