FORMA

复用机制:Mixin 与继承

Sass 提供两类核心的样式复用机制:Mixin@mixin / @include,支持参数与内容块)与 继承@extend%placeholder,通过合并选择器减少重复)。两者适用场景不同,本文末尾给出对比与选择建议。跨文件使用时需先 @use 引入模块,例如 @use "mixins" as m;@include m.clearfix;(见 模块与控制流)。

一、Mixin(@mixin / @include

1. 定义与调用(无参数)

最简单的 Mixin 不接收参数,封装一组通用样式。

scss
// 定义
@mixin clearfix {
  &::after {
    content: "";
    display: table;
    clear: both;
  }
}

// 调用
.container {
  @include clearfix;
}

编译后:

css
.container::after {
  content: "";
  display: table;
  clear: both;
}

适用于无需配置的通用模式(如清除浮动、文本截断等)。

2. 带参数的 Mixin

通过参数使 Mixin 更灵活,可设置默认值。

scss
// 定义:第二个参数有默认值
@mixin button($bg-color, $text-color: white) {
  background: $bg-color;
  color: $text-color;
  padding: 10px 20px;
  border-radius: 4px;
}

// 调用
.primary-btn {
  @include button(#3498db); // 使用默认文字颜色
}

.secondary-btn {
  @include button(#e74c3c, #333); // 两个参数都指定
}

编译结果:

css
.primary-btn {
  background: #3498db;
  color: white;
  padding: 10px 20px;
  border-radius: 4px;
}
.secondary-btn {
  background: #e74c3c;
  color: #333;
  /* ... */
}

支持关键字参数,提高可读性:

scss
@include button($bg-color: #f39c12, $text-color: #fff);

3. 可变参数(...

当参数个数不确定时,使用 $args... 将所有参数作为列表传递给 Mixin。

scss
// 定义
@mixin box-shadow($shadows...) {
  box-shadow: $shadows;
}

// 调用:可传入任意数量的阴影
.card {
  @include box-shadow(0 2px 4px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.1));
}

编译后:

css
.card {
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.1),
    0 4px 8px rgba(0, 0, 0, 0.1);
}

可变参还支持将列表值传递给其他 Mixin 或函数。

4. 内容块(@content

@content 允许调用者向 Mixin 中传递一整块样式代码,实现高度定制。

scss
// 定义:响应式断点 Mixin
@mixin respond-to($breakpoint) {
  @media (min-width: $breakpoint) {
    @content; // 调用时传入的内容会放置在此处
  }
}

// 调用
.sidebar {
  width: 100%;

  @include respond-to(768px) {
    width: 30%; // 这段样式会插入到 @content 位置
  }
}

编译后:

css
.sidebar {
  width: 100%;
}
@media (min-width: 768px) {
  .sidebar {
    width: 30%;
  }
}

典型应用:媒体查询封装、主题切换(暗色/亮色)、复杂动画的定制。

5. Mixin 的不足

不足说明示例场景
CSS 冗余每次 @include 都会完整输出一份样式代码,多次调用会产生重复 CSS若在10个地方调用同一个无参数的 clearfix,CSS 中会出现10份完全相同的代码块
无法合并选择器即使样式完全一样,也不会自动合并@extend 不同,Mixin 不会用逗号合并选择器
调试稍复杂浏览器调试时看到的是展开后的完整代码,不易追溯到 Mixin 源适合配合 sourcemap 使用

二、继承与占位符

1. @extend 继承

@extend 允许一个选择器继承另一个选择器的样式,编译后多个选择器会被合并到同一条 CSS 规则中,从而减少冗余。

scss
.message {
  padding: 10px;
  border: 1px solid #ccc;
}

.success {
  @extend .message;
  border-color: green;
}

.error {
  @extend .message;
  border-color: red;
}

编译结果:

css
.message,
.success,
.error {
  padding: 10px;
  border: 1px solid #ccc;
}
.success {
  border-color: green;
}
.error {
  border-color: red;
}

优点:生成的 CSS 体积更小(相同样式只出现一次)。

缺点

  • 不能传递参数,灵活性差。
  • 可能会生成较长的选择器列表(当继承链较深时)。
  • 不能在 @media 内部直接使用 @extend 继承外部规则(除非该选择器也在同一声明块内)。

2. 占位符选择器 %placeholder

占位符是以 % 开头的特殊选择器,本身不会生成 CSS,只有通过 @extend 被引用时,引用它的选择器才会出现在编译结果中。这使得占位符非常适合定义“抽象基类”,避免污染全局命名空间。

scss
%flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.header {
  @extend %flex-center;
}

.footer {
  @extend %flex-center;
}

编译结果:

css
.header,
.footer {
  display: flex;
  justify-content: center;
  align-items: center;
}

占位符的限制

  • 必须定义在顶层作用域(不能在规则内部或媒体查询内部定义)。
  • 不支持复合选择器(如 %foo:hover 会报错)。
  • 不能直接在媒体查询内定义,但可以在媒体查询内 @extend 外部定义的占位符。

如何处理响应式场景:通常结合 Mixin 来传递媒体查询逻辑。例如:

scss
%flex-column {
  flex-direction: column;
}

@mixin responsive-column {
  @media (max-width: 768px) {
    @extend %flex-column;
  }
}

三、@extend / 占位符 vs @mixin 对比

特性@extend / 占位符@mixin
输出方式合并选择器,生成一条共享规则每次调用直接复制样式代码
CSS 体积通常更小(无重复)可能因多次调用产生大量重复代码
参数支持❌ 不支持✅ 支持
条件分支(@if❌ 不支持✅ 支持
@content 内容块❌ 不支持✅ 支持
适用场景样式完全相同的静态复用需要动态值或条件逻辑
可维护性修改一处,所有继承处自动更新需重新编译所有 @include

选择建议

  • 需要参数内容块 → 使用 @mixin
  • 样式完全相同且无需参数 → 优先考虑 @extend 或占位符(%placeholder)以减少 CSS 体积
  • 不要为每个小组件都使用 @extend,否则选择器列表过长,可能导致 gzip 后体积不减反增,且增加浏览器匹配开销。

四、注意事项与反模式

  1. 避免链式继承过深%a → %b → %c 会导致最终选择器列表非常长(.a, .b, .c, .d ...),影响浏览器解析速度。
  2. 警惕选择器爆炸:如果大量使用 @extend 组合,编译后的选择器列表可能包含上百个类名,反而降低性能并增大 CSS 体积。
  3. 不要在媒体查询内继承外部选择器:Sass 不允许跨 @media 作用域继承(会报错)。正确的做法是将公共样式定义为 %placeholder,然后在媒体查询内 @extend(占位符须在外部定义),或使用 Mixin 配合 @content
  4. 使用占位符代替普通类继承:当继承的目标不是实际 DOM 中使用的类(即仅作为样式基类),应使用 %placeholder 而非普通 .class,以避免产生无关的 CSS 类名。

总结

特性语法用途
Mixin 定义@mixin name { ... }创建可复用块
Mixin 调用(无参)@include name;使用无参混合
带参数@mixin name($param, $default: val)配置化样式
可变参数@mixin name($args...)接收不定数量参数
内容块@content + @include name { ... }注入自定义样式
@extend.a { @extend .b; }合并选择器,减少重复
%placeholder%name { ... } + @extend %name抽象基类,不生成无用 CSS

需要参数或注入代码块时用 Mixin;样式完全相同且无参的静态复用优先评估 @extend 或占位符,以在可维护性与输出 CSS 体积之间取得平衡。

参考文献

资料说明
Sass:@mixin定义与 @content
Sass:@include调用 mixin
Sass:@extend继承与占位符