Sass 代码复用完全指南:从变量到模块化

在编写 CSS 时,"不要重复自己"是永恒的追求。然而原生 CSS 缺乏变量、函数、继承等机制,导致我们不得不一遍遍复制相同的颜色值、相同的布局模式,项目越大越难维护。

Sass 作为最成熟的 CSS 预处理器,提供了一整套代码复用工具------从基础的变量、嵌套,到强大的混入、继承、函数、循环,再到现代的模块化体系。本文结合日常项目开发场景,部分引用Sass 官方文档示例,梳理相关复用手段,帮你写出更简洁、更可维护的样式代码。

1. 变量:让值"活"起来

最基础的复用,是把重复出现的值绑定到一个变量上。Sass 变量以 $ 开头,可以存放颜色、尺寸、字体堆、甚至整个映射(map)。

scss 复制代码
$font-stack:    Helvetica, sans-serif;
$primary-color: #333;
$border:        1px solid #ccc;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

适用场景 :整个项目层面的设计标记(design tokens)。

复用本质:值的集中管理,一处修改,全局更新。

2. 嵌套:减少选择器重复

Sass 允许按 HTML 的结构嵌套编写选择器,大幅减少重复书写父级选择器。

scss 复制代码
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  li { display: inline-block; }
  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

编译后成为 nav ulnav linav a,省去了手动重复 nav 前缀的麻烦。

适用场景 :组件内部层级关系明确时。

注意:避免过深嵌套(一般不超过 3 层),否则生成的长选择器会影响性能与可维护性。

3. 混入(Mixin):参数化的代码块

如果说变量复用的是"值",混入复用的则是"一组样式规则",并且可以接受参数来动态变化。

scss 复制代码
@mixin text-overflow($lines: 1) {
  @if $lines == 1 {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  } @else {
    display: -webkit-box;
    -webkit-line-clamp: $lines;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

.card-title    { @include text-overflow(2); }
.news-headline { @include text-overflow(3); }

这里通过参数 $lines 控制单行还是多行截断,相同的模式,不同的输出。

适用场景 :需要跨组件共享、且可能因参数而异的样式模式。

复用本质:代码块的复制粘贴自动化,但每次调用都会生成完整的属性集。

4. 继承(Extend)与占位符:选择器层面的复用

与混入的"代码块复制"不同,@extend 是在选择器之间建立一种"并集"关系。它告诉 Sass:"让这个选择器共享那个选择器上已经存在的所有规则"。

示例1:Sass 官网一套错误、警告、成功的消息框

scss 复制代码
// 占位符选择器:仅在扩展时才输出
%message-shared {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}

// 未使用的占位符永远不会出现在 CSS 中
%equal-heights {
  display: flex;
  flex-wrap: wrap;
}

.message { @extend %message-shared; }
.success { @extend %message-shared; border-color: green; }
.error   { @extend %message-shared; border-color: red; }
.warning { @extend %message-shared; border-color: yellow; }

编译为:

css 复制代码
.message, .success, .error, .warning {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}
.success { border-color: green; }
.error   { border-color: red; }
.warning { border-color: yellow; }

关键优势

  • 共用一份基础规则,CSS 体积更小。
  • 不需要在 HTML 上堆叠多个类名(如 class="message message-shared"),更干净。
  • 占位符 % 不会被输出,未使用的 %equal-heights 完全消失,保证 CSS 整洁。

示例2:项目中有大量相同尺寸、不同背景的图标

scss 复制代码
%icon-base {
  width: 24px;
  height: 24px;
  display: inline-block;
  background-size: contain;
  background-repeat: no-repeat;
}

.icon-home   { @extend %icon-base; background-image: url('/icons/home.svg'); }
.icon-user   { @extend %icon-base; background-image: url('/icons/user.svg'); }
.icon-search { @extend %icon-base; background-image: url('/icons/search.svg'); }

适用场景 :多个选择器共享完全相同的样式,呈现"静态继承"关系。

复用本质:选择器的合并,编译后形成群组选择器。

5. 混入 vs 继承:如何选择?

这是 Sass 用户最常纠结的问题。看一个对比:

特性 Mixin Extend + 占位符
参数 支持 不支持
CSS 输出 每次调用复制一份属性 共用一套规则,体积更小
灵活性 高,可按参数变化 低,只能原样继承
HTML 类名 不需要额外类名 不需要额外类名
适用场景 需要根据上下文变化的动态样式模式 具有继承语义的关系,如变量主题、基础样式

决策口诀

  • 需要传参动态生成不同样式 → 用 Mixin。
  • 多个选择器无条件共享同一组样式 → 用 Extend + 占位符。
  • 切忌把 Mixin 用在纯静态的基础属性上(比如所有按钮的圆角、内边距),否则会生成大量重复 CSS。@mixin 本身不会导致体积膨胀,但是滥用 @include 特别在循环、深层嵌套或跨组件重复调用时,它会把同一段样式原样复制多遍。

6. 函数:带返回值的复用

Sass 支持自定义函数,可以像编程语言一样封装计算逻辑,返回值供属性使用。这也是代码复用的高级形式------逻辑的复用。

示例1:流体网格计算,复用比例逻辑

scss 复制代码
@use "sass:math";

@function col-width($col, $total: 960px) {
  @return math.div($col, $total) * 100%;
}

.main { width: col-width(600px); }
.side { width: col-width(300px); }

示例2:自动生成悬停色

scss 复制代码
@use "sass:color";

@function hover-darken($color, $amount: -10%) {
  @return color.adjust($color, $lightness: $amount);
}

.button {
  background: #06c;
  &:hover {
    background: hover-darken(#06c);
  }
}

适用场景 :重复的计算逻辑、需要根据输入动态返回值的场景。

复用本质:逻辑封装,将公式或算法集中管理。

7. 循环迭代:批量生成类

当需要为大量相似但不同的元素生成样式时,@each@for 是消解重复的利器。

示例1:用 @each 生成图标类

结合前面的 %icon-base,我们可以用 @each 批量生成:

scss 复制代码
%icon-base {
  width: 24px; height: 24px;
  display: inline-block;
  background-size: contain;
  background-repeat: no-repeat;
}

$icons: (
  "home":   "/icons/home.svg",
  "user":   "/icons/user.svg",
  "search": "/icons/search.svg",
  "settings": "/icons/settings.svg"
);

@each $name, $url in $icons {
  .icon-#{$name} {
    @extend %icon-base;
    background-image: url($url);
  }
}

示例2:用 @for 生成栅格列

scss 复制代码
@use "sass:math";

@for $i from 1 through 12 {
  .col-#{$i} {
    width: math.div(100%, 12) * $i;
  }
}

适用场景 :有一组按规律变化的类名或数值,需要批量生成。

复用本质:生成式复用,用循环代替手动罗列。

8. 模块化体系:跨文件的大规模复用

从 Dart Sass 1.33.0 开始,@use@forward 成为组织代码的标准,彻底告别了 @import 的全局污染。

scss 复制代码
// _variables.scss
$primary: #036;
$border-radius: 4px;

// _mixins.scss
@mixin btn-base {
  border-radius: $border-radius;
  padding: 8px 16px;
}

// style.scss
@use 'variables' as vars;
@use 'mixins';

.btn-primary {
  @include mixins.btn-base;
  background: vars.$primary;
  color: white;
}

配合内置模块(sass:mathsass:colorsass:string 等),我们可以构建自己的函数库、混入库、设计标记库,然后在任何组件中按需引入,既复用了代码,又隔离了作用域。

9. 总结

CSS 代码复用的根本目的不是压缩体积,而是降低认知负担和维护成本。在合适的场景选择合适的工具,你的样式表就能保持健壮、清晰且长期可控。

相关推荐
张拭心1 小时前
Android 17 新特性:后台音频交互限制加强
android·前端
张拭心1 小时前
Android 17 新特性:ProfilingManager 新触发器
android·前端
weixin_471383032 小时前
Taro-03-页面生命周期
前端·javascript·taro
张拭心2 小时前
Android 17 新特性:MessageQueue 无锁实现
android·前端
Asize2 小时前
数组数据结构底层:从灵活到陷阱
前端·javascript·算法
十九画生2 小时前
Ajax 入门:用 XHR 理解前后端异步请求
前端·javascript·后端
yingyima2 小时前
Python re 模块速查:从实战对比中掌握正则表达式
前端
放下华子我只抽RuiKe53 小时前
FastAPI 全栈后端(三):数据库与 ORM
前端·数据库·react.js·oracle·性能优化·前端框架·fastapi
梵得儿SHI3 小时前
Vue 项目实战与性能优化全攻略:从代码、渲染到首屏,一站式解决卡顿慢加载
前端·vue.js·性能优化·vite·前端面试·前端优化·首屏优化