一、为什么我们要告别@import

以前我们在写Sass的时候,最常用的就是@import来引入其他文件。就像去超市买东西,把所有商品都扔进同一个购物车。但随着项目越来越大,这种方式开始暴露出问题:

  1. 所有变量和混合器都混在全局命名空间里,容易冲突
  2. 无法控制哪些成员应该被外部访问
  3. 重复导入会导致代码冗余

举个例子,假设我们有两个文件:

// 技术栈:Sass
// _colors.scss
$primary: #ff0000;
$secondary: #00ff00;

// _buttons.scss
@import 'colors';
.button {
  background-color: $primary;
}

这种情况下,任何导入_buttons.scss的文件都会自动获得_colors.scss中的所有变量,完全没有隔离性可言。

二、认识新的模块系统:@use和@forward

Sass官方在2019年推出了模块系统,提供了两个新指令来解决这些问题。

1. @use的基本用法

@use更像是按需导入,它会创建一个独立的命名空间:

// 技术栈:Sass
// styles.scss
@use 'colors'; // 引入_colors.scss文件

.header {
  color: colors.$primary; // 需要通过模块名访问变量
}

这样做的优点是:

  • 变量不会污染全局空间
  • 明确知道变量来自哪个文件
  • 可以避免命名冲突

2. @forward的桥梁作用

@forward允许我们把多个文件组织成一个"包":

// 技术栈:Sass
// _theme.scss
@forward 'colors';
@forward 'typography';

// main.scss
@use 'theme';
body {
  color: theme.$text-color; // 实际定义在_typography.scss中
}

三、深入理解命名空间管理

1. 自定义命名空间

默认情况下,模块名就是文件名,但我们可以自定义:

// 技术栈:Sass
@use 'colors' as c; // 使用c作为命名空间
@use 'buttons' as b;

.alert {
  color: c.$danger;
  @include b.large-button;
}

2. 私有成员的控制

通过在变量或混合器名前添加下划线,可以将其设为私有:

// 技术栈:Sass
// _utils.scss
$_internal-padding: 10px; // 私有变量,外部无法访问
@mixin _reset-list {      // 私有混合器
  margin: 0;
  padding: 0;
}

@mixin styled-list {
  @include _reset-list; // 内部可以访问私有成员
  li {
    padding: $_internal-padding;
  }
}

四、实际应用场景与最佳实践

1. 组件化开发场景

假设我们在开发一个UI组件库:

// 技术栈:Sass
// components/_index.scss
@forward 'button';
@forward 'card';
@forward 'modal';

// styles/main.scss
@use 'components' as comp;

.login-card {
  @include comp.card;
  .submit-btn {
    @include comp.button(primary, large);
  }
}

2. 主题系统实现

// 技术栈:Sass
// _light-theme.scss
$primary-color: #1976d2 !default;
$text-color: #333 !default;

// _dark-theme.scss
$primary-color: #90caf9 !default;
$text-color: #fff !default;

// _theme.scss
@forward 'light-theme' as light-*;
@forward 'dark-theme' as dark-*;

// app.scss
@use 'theme' with (
  $light-primary-color: #1565c0,
  $dark-text-color: #f5f5f5
);

五、技术优缺点分析

优点:

  1. 解决了命名冲突问题
  2. 代码组织结构更清晰
  3. 实现了真正的封装性
  4. 按需加载提高性能

缺点:

  1. 学习曲线比@import高
  2. 需要修改现有项目结构
  3. 部分老版本工具链不支持

六、迁移注意事项

  1. 逐步替换,不要一次性全部修改
  2. 注意变量访问方式的变化
  3. 检查第三方库是否支持新语法
  4. 更新构建工具的Sass编译器版本

七、完整示例演示

让我们看一个完整的组件库示例:

// 技术栈:Sass
// foundation/_index.scss
@forward 'colors';
@forward 'typography';
@forward 'spacing';

// components/button/_index.scss
@use '../../foundation' as f;

$-button-padding: 0.5rem 1rem !default; // 私有配置

@mixin base {
  padding: $-button-padding;
  border-radius: 4px;
  font-family: f.$font-family;
}

@mixin primary {
  @include base;
  background-color: f.$primary;
  color: white;
}

// app.scss
@use 'components/button' as btn;

.submit-btn {
  @include btn.primary;
}

八、总结与建议

新的模块系统代表了Sass未来的发展方向。虽然迁移过程可能需要一些时间,但带来的好处是显而易见的。对于新项目,建议直接使用@use和@forward;对于老项目,可以制定渐进式的迁移计划。

在实际使用中,建议:

  1. 合理组织文件结构
  2. 善用私有成员保护内部实现
  3. 使用_index.scss文件作为模块入口
  4. 给重要的公共API添加详细注释

通过良好的模块化实践,可以让你的Sass代码更易于维护、扩展和复用。