返回首页

Sass @use & @forward:扩展 CSS 的模块化架构

本文详述了 Sass 从过时的 @import 向现代 @use 和 @forward 指令的过渡。它解释了命名空间的工作原理、模块配置,以及为可扩展且易维护的 CSS 架构创建公共 API。

Sass 精通:@use 和 @forward 用于现代 CSS 架构
Advertisement 728x90

Sass:从传统 @import 到基于 @use 和 @forward 的现代模块化架构

在前端开发领域,随着项目日益复杂和代码库不断膨胀,高效的样式管理变得至关重要。Sass 作为领先的 CSS 预处理器之一,为了增强代码的模块化和可维护性,经历了一系列重大变革。其中一个关键的演进步骤,就是从已弃用的 @import 指令转向功能强大且灵活的 @use@forward

长期以来,@import 是引入 Sass 文件的唯一方式,但它也带来了显著的弊端:全局命名空间污染、高冲突风险以及代码重复。随着 Dart Sass 3.0.0 的即将发布,@import 已被官方弃用,并将被彻底移除,这使得所有现代开发者都必须采纳新的模块化系统。

@use 指令:隔离与命名空间

@use 是 Sass 新模块化系统的核心元素。它加载一个 Sass 文件(模块),并使其内容(变量、混入、函数)在当前文件中可用,但将其隔离在自己的命名空间内。这与 @import 有着关键区别,它能有效防止全局冲突,并使依赖关系更加明确。

Google AdInline article slot

基本用法:

@use 'path/to/file';

默认情况下,命名空间的名称来源于文件路径的最后一部分,不包含下划线或文件扩展名。例如,当使用 @use '../helpers/colors'; 时,来自 _colors.scss 的变量和函数将通过 colors. 前缀访问:

// helpers/_colors.scss
$primary: blue;
$secondary: gray;
// components/_button.scss
@use '../helpers/colors';

.button {
  color: colors.$primary; // Accessed via the "colors" namespace
  background-color: colors.$secondary;
}

使用 as 更改命名空间:

Google AdInline article slot

为了方便或清晰起见,你可以使用 as 关键字为模块指定一个自定义名称:

@use 'helpers/colors' as myColors;

.button {
  color: myColors.$primary; // Accessed via "myColors"
}

在命名命名空间时,应遵循 Sass 标识符规则:

  • 允许: 字母 (a-z, A-Z)、数字 (0-9,但不能作为开头)、camelCase(驼峰命名法)、PascalCase(帕斯卡命名法)。
  • 不允许: 连字符 (-)、空格、特殊字符、以数字开头。

利用 Sass 的内置模块

Sass 提供了一系列内置模块,用于处理常见的任务,例如数学运算、列表操作、映射(map)、颜色处理和字符串操作。这些模块通过 sass: 前缀导入:

Google AdInline article slot
@use 'sass:math';
@use 'sass:list';
@use 'sass:map';
@use 'sass:color';
@use 'sass:string';

内置模块函数的使用示例:

$width: math.div(100%, 3); // Division
$len: list.length((10px, 20px, 30px)); // List length
$color: color.adjust(#336699, $lightness: 20%); // Color adjustment
$index: string.index('hello world', 'world'); // Substring search

至关重要的是,请记住内置模块,就像常规模块一样,必须在使用其函数的每个文件中显式导入。它们不会通过其他导入而继承。

代码组织与模块访问

Sass 模块化系统鼓励这样一种方法:每个 SCSS 文件都在开头显式声明其依赖项。这确保了透明性并简化了重构。自定义文件中定义的混入和函数也可以通过命名空间访问。

混入定义示例:

// helpers/_mixins.scss
@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

及其用法:

// components/_card.scss
@use '../helpers/mixins';

.card {
  @include mixins.flex-center;
}

推荐的文件夹结构:

一个结构良好的 Sass 项目可能如下所示:

scss/
  helpers/
    _colors.scss
    _variables.scss
    _mixins.scss
  components/
    _button.scss
    _card.scss
  pages/
    _about-page.scss
  template.scss // Main build file

使用多个模块的组件文件示例:

// components/_button.scss
@use '../helpers/colors' as myColors;
@use '../helpers/variables';
@use '../helpers/mixins';

.button {
  background-color: myColors.$primary;
  padding: variables.$spacing-md;
  @include mixins.border-radius;
}

带有命名空间的模块化方法的优势:

  • 清晰性: 变量或混入来自哪个模块一目了然,提高了代码可读性。
  • 无冲突: 隔离的命名空间确保了不同模块中同名变量和混入不会发生冲突。
  • 更易重构: 只要 API 保持不变,一个模块的更改不会影响其他模块,从而简化了扩展和修改。
  • IDE 支持: 现代开发环境与显式命名空间配合得更好,提供了准确的自动补全功能。
  • 可扩展性: 即使在非常大型的项目中,代码库也能保持易于理解和管理。

使用 @use ... with() 配置模块

@use ... with() 指令提供了一种强大的机制,用于在导入时配置模块。它允许你通过在导入模块时直接传递新值来覆盖标记为 !default 的变量。

!default 的工作原理:

!default 声明的变量,仅在其之前未被设置过值时才使用其默认值。如果该值已被确立(例如,在另一个文件或通过 @use ... with()),则 !default 将被忽略。

// helpers/_theme.scss
$bg-color: #ffffff !default; // Default value
$text-color: #333333 !default; // Can be overridden

使用 with() 覆盖值:

你可以在导入模块时,在 with() 括号内为 !default 变量传递新值:

// pages/dark-theme.scss
@use '../helpers/theme' with (
  $bg-color: #1a1a1a,
  $text-color: #f0f0f0
);

body {
  background: theme.$bg-color; // Will be #1a1a1a
  color: theme.$text-color; // Will be #f0f0f0
}

关于 with() 的重要注意事项:

  • @use ... with() 仅在给定文件中首次导入特定模块时有效。所有后续尝试以不同 with() 值导入同一模块的操作都将被忽略。
  • 许多第三方 Sass 库使用 !default 来设置其配置,从而可以通过 with() 轻松自定义其行为。

@forward 指令:构建公共 API

@forward 是一个指令,它允许你重新导出(re-export)一个或多个模块的内容,使它们可供导入中间文件的其他文件使用。它用于为一组模块创建一个单一的入口点(公共 API),而无需在使用 @forward 的文件中直接访问这些模块的内容。

使用 _core.scss 作为单一入口点的示例:

// _core.scss
@forward 'helpers/colors';
@forward 'helpers/variables';
@forward 'base/fonts';
@forward 'helpers/mixins';

现在,你无需单独导入每个文件,只需导入 _core.scss 即可:

// pages/about-page.scss
@use '../core.scss';

.button {
  color: core.$blue; // Variable from helpers/colors
  border-radius: core.$border-radius-medium; // Variable from helpers/variables
  @include core.flex-center; // Mixin from helpers/mixins
}

_core.scss 方法的优缺点:

  • 优点: 简化了消费文件中的导入,为整个项目创建了清晰的 API。
  • 缺点: 所有转发的元素都使用 core 命名空间(或你指定的命名空间),这可能使得在不检查 _core.scss 的情况下,难以确定特定变量或混入的原始文件。

转发模块的内部使用:

如果 _core.scss 文件本身需要使用来自转发模块的变量或混入,它必须使用 @use 显式导入它们:

// _core.scss
@forward 'helpers/colors'; // Forwarding outwards
@use 'helpers/colors' as c; // For internal use within _core.scss

body {
  background: c.$bg-color; // Works thanks to @use
}

@forward 的高级功能:

  • 选择性转发 (show / hide): 允许你显式指定模块中哪些元素应该被转发。

```scss

@forward 'colors' show $primary, $secondary; // Forward only these variables

@forward 'mixins' hide private-mixin; // Forward all except private-mixin

```

  • 转发时通过 with() 进行配置: 类似于 @use ... with(),你可以在转发模块时覆盖 !default 变量。

```scss

// helpers/_theme.scss

$bg-color: #fff !default;

// _index.scss (file that will forward _theme.scss)

@forward 'theme' with (

$bg-color: #f0f0f0

);

```

管理模块依赖

在 Sass 模块化系统中,每个文件都必须显式声明其依赖项。即使你的某个模块(例如 _variables.scss)使用了来自另一个模块(例如 _colors.scss)的变量,这条规则也适用。即使 _variables.scss_colors.scss 都通过 _core.scss 转发,如果 _variables.scss 使用了 _colors.scss 的内容,它仍然必须显式导入 _colors.scss

// _variables.scss
@use 'colors'; // Explicit dependency on _colors.scss

$button-bg: colors.$primary;

为什么这很重要:

  • 清晰性: 每个文件依赖哪些模块一目了然,简化了对项目结构的理解。
  • 可靠性: 当文件被移动或重组时,依赖关系保持完整且易于理解。
  • IDE 支持: 静态分析工具和自动补全功能工作更准确。
  • 重构: 很容易追踪特定模块和变量的使用位置。

核心要点

  • @use 和 @forward 取代了已弃用的 @import,为 Sass 提供了真正的模块化能力。
  • 命名空间 防止冲突并使依赖关系明确,从而提高了可扩展性。
  • @use ... with() 通过覆盖标记为 !default 的变量,实现了灵活的模块配置。
  • @forward 用于创建单一入口点(公共 API),简化了大量模块的管理。
  • 在每个文件中显式声明依赖项 对于 Sass 代码的可维护性和可预测性至关重要。

— Editorial Team

Advertisement 728x90

继续阅读