前言
今天在翻阅 Element-plus 的官网的时候,看到了一个警告:
觉得蛮好奇,为什么 Sass 团队会在接下来进行删除 @import 语法。
@import 的缺陷
Sass 扩展了 CSS 的 @import 规则,能够导入 Sass 和 CSS 样式表,提供对 mixin、函数和变量的访问,并将多个样式表的 CSS 组合在一起。与普通的 CSS 导入不同,后者要求浏览器在呈现页面时发出多个 HTTP 请求,Sass 导入完全在编译期间处理。但是这个语法有如下的缺点:
@import使所有变量、mixin 和函数都可以全局访问。这使得人们(或工具)很难分辨出任何东西是在哪里定义的,比如两个 mixin 文件中有相同的名称,这会导致非预期的结果。- 因为一切都是全局的,所以库必须为其所有成员添加前缀以避免命名冲突。
@extend规则也是全局的,这使得很难预测哪些样式规则将被扩展。- 每个样式表都会在每次
@imported时执行并发出其 CSS,这会增加编译时间并产生臃肿的输出。 - 无法定义下游样式表无法访问的私有成员或占位符选择器。
Sass 将在接下来的几年中逐步淘汰它,并最终将其从语言中完全删除。
@use 的优点
@use 规则从其他 Sass 样式表中加载 mixins、函数和变量,并将来自多个样式表的 CSS 组合在一起。 @use 加载的样式表称为“模块”。 最简单的@use 规则是@use "url",它在给定的URL 加载模块。以这种方式加载的任何样式都将在编译的 CSS 输出中仅包含一次,无论这些样式被加载多少次。
加载成员
使用 @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;
}
得到的 css:
.button {
border-radius: 3px;
padding: 8px;
}
类似的,你也可以设置别名:
@use "src/corners" as c;
私有成员
开发样式表,有时候可能不希望定义的所有成员都在您的样式表之外可用。 Sass 通过以 - 或 _ 开头的名称来定义私有成员。这些成员将在定义它们的样式表中正常工作,但它们不会成为模块公共 API 的一部分。这意味着加载您的模块的样式表看不到它们。
// src/_corners.scss
$-radius: 3px;
@mixin rounded {
border-radius: $-radius;
}
// style.scss
@use "src/corners";
.button {
@include corners.rounded;
// 这里将会抛出错误! $-radius 在`_corners.scss`中不是可用的值.
padding: 5px + corners.$-radius;
}
可配置项
样式表可以使用 !default 标志定义变量以使它们可配置。要加载带有配置的模块,需使用@use <url> with (<variable>: <value>, <variable>: <value>)。配置的值将覆盖变量的默认值。
// _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
);
code {
border-radius: 0.1rem;
box-shadow: 0 0.5rem 1rem rgba(34, 34, 34, 0.15);
}
在使用 @use ... with 语法配置模块中含有特别多的值时,它并不是特别灵活。如果您发现自己想要一次配置多个变量,将映射作为配置传递,或者在模块加载后更新配置,请考虑编写一个 mixin 来设置您的变量,然后再编写一个 mixin 来注入您的样式。
// _library.scss
$-black: #000;
$-border-radius: 0.25rem;
$-box-shadow: null;
// 如果使用者配置过 `$-box-shadow`, 返回配置的值。
// 否则返回一个派生自 `$-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;
得到的 css:
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
局部模块
和之前一样,仅打算作为模块加载而不是自行编译的 Sass 文件以 _ 开头(如 _code.scss 中)。这些被称为局部模块,它们告诉 Sass 工具不要尝试自己编译这些文件。导入部分时,您可以省略 _。
@use 的好伙伴 @forward
@forward 可以加载 Sass 样式表,搭配 @use 可以使多个文件编织在一起,成为单个入口点文件。
基础使用
// src/_list.scss
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss
@forward "src/list";
// styles.scss
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
得到的 css
li {
margin: 0;
padding: 0;
list-style: none;
}
统一添加前缀
// src/_list.scss
@mixin reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss
@forward "src/list" as list-*;
// styles.scss
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
li {
margin: 0;
padding: 0;
list-style: none;
}
控制可见性
有时,您不想转发模块中的每个成员。您可能希望将某些成员保密,以便只有您的包可以使用它们,或者您可能希望要求您的用户以不同的方式加载某些成员。
// src/_list.scss
$horizontal-list-gap: 2em;
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
@mixin list-horizontal {
@include list-rest;
li {
display: inline-block;
margin: {
left: -2px;
right: $horizontal-list-gap;
}
}
}
// bootstrap.scss
@forward "src/list" hide list-reset, $horizontal-list-gap;
可配置项
@forward 还可以加载带有配置的模块。这与 @use 的工作方式基本相同,但有一个补充:@forward 规则的配置可以在其配置中使用 !default 标志。这允许模块更改上游样式表的默认值,同时仍允许下游样式表覆盖它们。
// _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;
}
// _opinionated.scss
@forward 'library' with (
$black: #222 !default,
$border-radius: 0.1rem !default
);
// style.scss
@use 'opinionated' with ($black: #333);
注意点
- 目前只有 Dart Sass 支持
@use。其他版本必须使用@import规则。 - 官方目前提供了从
@import转换到@use的工具