在编写 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 ul、nav li、nav 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:math、sass:color、sass:string 等),我们可以构建自己的函数库、混入库、设计标记库,然后在任何组件中按需引入,既复用了代码,又隔离了作用域。
9. 总结
CSS 代码复用的根本目的不是压缩体积,而是降低认知负担和维护成本。在合适的场景选择合适的工具,你的样式表就能保持健壮、清晰且长期可控。