Sass @use 替代 @import

·  阅读 2276

前言

今天在翻阅 Element-plus 的官网的时候,看到了一个警告:

image.png

觉得蛮好奇,为什么 Sass 团队会在接下来进行删除 @import 语法。

@import 的缺陷

Sass 扩展了 CSS 的 @import 规则,能够导入 Sass 和 CSS 样式表,提供对 mixin、函数和变量的访问,并将多个样式表的 CSS 组合在一起。与普通的 CSS 导入不同,后者要求浏览器在呈现页面时发出多个 HTTP 请求,Sass 导入完全在编译期间处理。但是这个语法有如下的缺点:

  1. @import使所有变量、mixin 和函数都可以全局访问。这使得人们(或工具)很难分辨出任何东西是在哪里定义的,比如两个 mixin 文件中有相同的名称,这会导致非预期的结果。
  2. 因为一切都是全局的,所以库必须为其所有成员添加前缀以避免命名冲突。
  3. @extend 规则也是全局的,这使得很难预测哪些样式规则将被扩展。
  4. 每个样式表都会在每次@imported时执行并发出其 CSS,这会增加编译时间并产生臃肿的输出。
  5. 无法定义下游样式表无法访问的私有成员或占位符选择器。

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工具
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改