Skip to content
On this page

Sass 模块系统

Sass模块系统是Sass 4.0引入的重要功能,旨在替代旧的@import系统,提供更好的性能、作用域隔离和依赖管理。本章将详细介绍Sass模块系统的使用方法和优势。

模块系统概述

Sass模块系统使用@use规则替代传统的@import规则,提供了以下优势:

  • 作用域隔离:模块中的变量、函数和混合宏不会污染全局命名空间
  • 性能提升:模块只会被加载一次,即使在多个地方使用
  • 明确的依赖关系:可以清楚地看到每个文件依赖了哪些模块

@use 规则基础

scss
// _variables.scss - 定义变量模块
$primary-color: #007bff;
$secondary-color: #6c757d;
$font-size-base: 16px;
$border-radius: 4px;

// _functions.scss - 定义函数模块
@function px-to-rem($px, $base: 16px) {
  @return ($px / $base) * 1rem;
}

@function calculate-opacity($color, $alpha: 1) {
  @return rgba($color, $alpha);
}

// _mixins.scss - 定义混合宏模块
@mixin button-style($bg-color: #007bff, $text-color: white) {
  background-color: $bg-color;
  color: $text-color;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: $border-radius;
  cursor: pointer;
  
  &:hover {
    background-color: darken($bg-color, 10%);
  }
}

// main.scss - 使用模块
@use 'variables';
@use 'functions';
@use 'mixins';

.element {
  color: variables.$primary-color;
  font-size: functions.px-to-rem(18px);
  
  .button {
    @include mixins.button-style(variables.$secondary-color);
  }
}

命名空间和别名

默认命名空间

scss
// _colors.scss
$primary: #007bff;
$secondary: #6c757d;

@function lighten-color($color, $amount: 10%) {
  @return lighten($color, $amount);
}

// _typography.scss
$font-family: 'Arial', sans-serif;
$font-size: 16px;

// main.scss
@use 'colors';
@use 'typography';

.card {
  background-color: colors.$primary;
  color: colors.lighten-color(colors.$primary, 20%);
  font-family: typography.$font-family;
  font-size: typography.$font-size;
}

使用as关键字设置别名

scss
// 为模块设置简短的别名
@use 'colors' as c;
@use 'typography' as t;
@use 'layout' as l;

.element {
  background-color: c.$primary;
  font-family: t.$font-family;
  padding: l.$standard-spacing;
}

// 避免命名冲突
@use 'button-styles' as btn;
@use 'form-styles' as form;

.submit-btn {
  @include btn.button-style;
}

.form-field {
  @include form.input-style;
}

顶级命名空间

scss
// 当文件名以_开头时,破折号会转换为驼峰命名
// _component-utils.scss
$default-padding: 1rem;
$default-margin: 0.5rem;

@function calculate-width($columns, $total-columns: 12) {
  @return percentage($columns / $total-columns);
}

// main.scss
@use 'component-utils' as utils;

.card {
  padding: utils.$default-padding;
  width: utils.calculate-width(6);
}

模块成员访问

变量访问

scss
// _theme.scss
// 默认导出所有以$开头的变量
$primary-color: #007bff;
$secondary-color: #6c757d;
$text-color: #333;

// 仅导出特定变量
$_internal-color: #f8f9fa; // 前缀下划线表示私有
$public-color: #28a745;

// 使用变量
@use 'theme';

.card {
  background-color: theme.$primary-color;
  color: theme.$text-color;
  border: 1px solid theme.$secondary-color;
}

函数访问

scss
// _math-helpers.scss
@function fibonacci($n) {
  @if $n <= 1 {
    @return $n;
  }
  @return fibonacci($n - 1) + fibonacci($n - 2);
}

@function clamp($value, $min, $max) {
  @return if($value < $min, $min, if($value > $max, $max, $value));
}

@function golden-ratio($value, $increment: 1) {
  $phi: 1.618033988749895;
  @return $value * pow($phi, $increment);
}

// _typography.scss
@use 'math-helpers' as math;

.text {
  font-size: math.golden-ratio(1rem, 1);
  max-width: math.clamp(100%, 300px, 800px);
}

混合宏访问

scss
// _grid.scss
@mixin container($max-width: 1200px) {
  max-width: $max-width;
  margin: 0 auto;
  padding: 0 1rem;
}

@mixin row {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -0.5rem;
}

@mixin col($width: 1) {
  flex: 0 0 percentage($width);
  padding: 0 0.5rem;
  box-sizing: border-box;
}

// main.scss
@use 'grid';

.main-container {
  @include grid.container(1400px);
  
  .content-row {
    @include grid.row;
    
    .sidebar {
      @include grid.col(0.25); // 25%
    }
    
    .main-content {
      @include grid.col(0.75); // 75%
    }
  }
}

模块路径和文件组织

相对路径导入

scss
// 在scss/components/_button.scss中
@use '../abstracts/variables' as vars;
@use '../abstracts/mixins' as mx;

.button {
  @include mx.button-style(vars.$primary-color);
  padding: vars.$spacing-md;
}

索引文件模式

scss
// scss/helpers/_index.scss (或 _index.scss)
@forward 'color-functions';
@forward 'math-functions';
@forward 'string-helpers';

// scss/helpers/color-functions.scss
@function contrast-color($color) {
  @return if(lightness($color) > 50, #000, #fff);
}

@function random-color() {
  @return rgb(random(255), random(255), random(255));
}

// main.scss
@use 'helpers' as h;

.element {
  color: h.contrast-color(#333);
  background-color: h.random-color();
}

@forward 规则

@forward规则允许一个模块转发另一个模块的内容。

基本转发

scss
// _private.scss
$secret-token: 'abc123';
$_internal-setting: 10px;

// _public.scss
@forward 'private'; // 转发所有公共成员

// main.scss
@use 'public';

// 可以访问private模块中的公共变量
.element {
  content: public.$secret-token;
}

限制转发内容

scss
// _all-config.scss
$api-url: 'https://api.example.com';
$timeout: 5000ms;
$_debug-mode: true;
$_log-level: 'verbose';

// _safe-config.scss
@forward 'all-config' hide $api-url, $_debug-mode; // 隐藏某些变量

// _admin-config.scss
@forward 'all-config' show $api-url, $timeout; // 只显示特定变量

// 使用限制转发的模块
@use 'safe-config';

// safe-config中不包含$api-url和$_debug-mode
.component {
  timeout: safe-config.$timeout; // 可以访问
  // api-url: safe-config.$api-url; // 错误:不可访问
}

使用as前缀

scss
// _colors.scss
$primary: #007bff;
$secondary: #6c757d;

// _branding.scss
@forward 'colors' as brand-*; // 添加前缀

// main.scss
@use 'branding';

.element {
  color: branding.$brand-primary;
  border-color: branding.$brand-secondary;
}

模块配置

使用with配置模块

scss
// _theme.scss
$primary-color: #007bff !default;
$secondary-color: #6c757d !default;
$border-radius: 4px !default;

.button {
  background-color: $primary-color;
  border-radius: $border-radius;
}

// _custom.scss
@use 'theme' with (
  $primary-color: #28a745,
  $border-radius: 8px
);

.custom-button {
  @include theme.button-style;
  // 使用配置后的变量值
}

模块配置最佳实践

scss
// _configurable-component.scss
$padding: 1rem !default;
$background: #f8f9fa !default;
$border-width: 1px !default;
$border-color: #dee2e6 !default;
$border-radius: 4px !default;

@use 'configurable-component' with (
  $background: #e9ecef,
  $border-color: #adb5bd
);

.component {
  padding: configurable-component.$padding;
  background-color: configurable-component.$background;
  border: configurable-component.$border-width solid configurable-component.$border-color;
  border-radius: configurable-component.$border-radius;
}

模块与现有代码的兼容性

混合使用@use和@import

scss
// 推荐:逐步迁移,先使用@use
@use 'new-module';
@use 'another-module';

// 仍然可以使用@import,但不推荐
@import 'legacy-file';

创建兼容性层

scss
// _compatibility.scss - 为旧代码提供兼容性
@use 'modern-theme' as theme;
@use 'modern-layout' as layout;

// 重新导出为全局变量(不推荐,仅用于迁移)
$primary-color: theme.$primary-color;
$grid-columns: layout.$columns;

@function get-primary() {
  @return theme.$primary-color;
}

@mixin grid-row {
  @include layout.row;
}

实际项目示例

项目结构

scss/
├── abstracts/
│   ├── _variables.scss
│   ├── _functions.scss
│   ├── _mixins.scss
│   └── _placeholders.scss
├── base/
│   ├── _reset.scss
│   ├── _typography.scss
│   └── _utilities.scss
├── components/
│   ├── _buttons.scss
│   ├── _cards.scss
│   └── _forms.scss
├── layouts/
│   ├── _grid.scss
│   ├── _header.scss
│   └── _footer.scss
├── pages/
│   ├── _home.scss
│   └── _about.scss
├── themes/
│   └── _default.scss
└── main.scss

抽象层模块

scss
// scss/abstracts/_variables.scss
// 颜色变量
$colors: (
  'primary': #007bff,
  'secondary': #6c757d,
  'success': #28a745,
  'danger': #dc3545,
  'warning': #ffc107,
  'info': #17a2b8
);

// 间距变量
$spacers: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 1rem,
  4: 1.5rem,
  5: 3rem
);

// 断点变量
$breakpoints: (
  'xs': 0,
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px,
  'xxl': 1400px
);

// scss/abstracts/_functions.scss
@function color($key) {
  @return map-get($colors, $key);
}

@function spacer($level) {
  @return map-get($spacers, $level);
}

@function breakpoint($key) {
  @return map-get($breakpoints, $key);
}

// scss/abstracts/_mixins.scss
@mixin respond-to($breakpoint) {
  @media (min-width: breakpoint($breakpoint)) {
    @content;
  }
}

@mixin button-variant($bg, $color: white) {
  background-color: $bg;
  color: if(lightness($bg) > 50, #212529, $color);
  
  &:hover {
    background-color: darken($bg, 10%);
  }
}

主入口文件

scss
// scss/main.scss
// 导入抽象层
@use 'abstracts/variables' as vars;
@use 'abstracts/functions' as func;
@use 'abstracts/mixins' as mx;

// 基础样式
@use 'base/reset';
@use 'base/typography';
@use 'base/utilities';

// 组件样式
@use 'components/buttons';
@use 'components/cards';
@use 'components/forms';

// 布局样式
@use 'layouts/grid';
@use 'layouts/header';
@use 'layouts/footer';

// 页面样式
@use 'pages/home';
@use 'pages/about';

// 使用模块内容
.page-wrapper {
  padding: func.spacer(3);
  
  @include mx.respond-to(md) {
    padding: func.spacer(4);
  }
  
  .primary-button {
    @include mx.button-variant(func.color('primary'));
  }
}

迁移指南

从@import迁移到@use

scss
// 旧的写法 (@import)
// main.scss
@import 'variables';
@import 'mixins';
@import 'buttons';

// 按钮样式可以直接使用变量和混合宏
.btn {
  @include button-style;
  background-color: $primary-color;
}

// 新的写法 (@use)
// main.scss
@use 'variables' as vars;
@use 'mixins' as mx;
@use 'buttons';

.btn {
  @include mx.button-style;
  background-color: vars.$primary-color;
}

创建迁移脚本

scss
// _migration-helper.scss
// 临时帮助迁移的模块
@use 'real-variables' as rv;
@use 'real-mixins' as rm;

// 重新导出以便逐步迁移
$primary-color: rv.$primary-color;
$secondary-color: rv.$secondary-color;

@mixin button-style {
  @include rm.button-style;
}

Sass模块系统提供了更好的代码组织方式和作用域管理,是现代Sass开发的推荐方式。