













在 Sass 中,@mixin 和 @extend 是两个非常重要的代码复用机制,但它们的工作方式和适用场景有显著的区别。理解这些区别对于写出高效、可维护的 Sass 代码至关重要。
| 维度 | @mixin (混合宏) |
@extend (继承) |
|---|---|---|
| 编译方式 | 复制代码:每次调用都会复制一份样式代码 | 合并选择器:将选择器合并到同一个规则集中 |
| 参数支持 | 支持:可以传递参数,动态生成样式 | 不支持:不能传递参数,只能静态继承 |
| 代码体积 | 可能导致代码重复,增加文件体积 | 代码更精简,减少重复代码 |
| 使用场景 | 需要根据参数动态变化的样式 | 具有完全相同样式规则的复用 |
| 媒体查询 | 可以在媒体查询内部定义和使用 | 有限制:不能在媒体查询内部继承外部样式 |
@mixin:参数化的代码复制器@mixin 就像是一个可以接收参数的函数,每次调用时,它会把定义的样式代码复制到当前选择器中。
// 定义 mixin
@mixin flex-center($direction: row) {
display: flex;
flex-direction: $direction;
justify-content: center;
align-items: center;
}
// 使用 mixin
.header {
@include flex-center;
}
.sidebar {
@include flex-center(column);
}
.footer {
@include flex-center;
}
编译后的 CSS:
.header {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.sidebar {
display: flex;
flex-direction: column; /* 参数不同,生成了不同的代码 */
justify-content: center;
align-items: center;
}
.footer {
display: flex;
flex-direction: row; /* 重复了和 header 相同的代码 */
justify-content: center;
align-items: center;
}
可以看到,.header 和 .footer 的样式代码是完全相同的,但都被复制了一份。
@extend:选择器的合并器@extend 不会复制代码,而是把当前选择器添加到被继承的规则集后面,形成选择器组。
// 定义一个基础样式类
.base-button {
padding: 10px 20px;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
}
// 继承基础样式
.primary-button {
@extend .base-button;
background-color: blue;
color: white;
}
.secondary-button {
@extend .base-button;
background-color: gray;
color: black;
}
.success-button {
@extend .base-button;
background-color: green;
color: white;
}
编译后的 CSS:
.base-button,
.primary-button,
.secondary-button,
.success-button {
padding: 10px 20px;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
}
.primary-button {
background-color: blue;
color: white;
}
.secondary-button {
background-color: gray;
color: black;
}
.success-button {
background-color: green;
color: white;
}
关键优势:基础样式只出现一次,所有继承它的选择器共享同一份样式规则。
@mixin 的场景@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
.avatar {
@include size(40px);
}
.cover {
@include size(100%, 200px);
}
@mixin transform($property) {
-webkit-transform: $property;
-ms-transform: $property;
transform: $property;
}
.box {
@include transform(rotate(45deg));
}
@mixin mobile {
@media (max-width: 768px) {
@content; // 允许传入额外的样式内容
}
}
.card {
width: 300px;
@include mobile {
width: 100%; // 移动端样式
}
}
@extend 的场景%clearfix {
&::after {
content: "";
display: table;
clear: both;
}
}
.container {
@extend %clearfix;
width: 100%;
}
.grid {
@extend %clearfix;
display: grid;
}
.error {
color: red;
font-weight: bold;
border: 1px solid red;
&:hover {
background-color: #ffeeee;
}
}
.validation-error {
@extend .error; // 继承所有 .error 的样式,包括 hover
font-size: 12px;
}
.server-error {
@extend .error;
padding: 20px;
}
结合你在 React 15 项目中使用 CSS Modules 的场景,这里有一些具体建议:
@mixin 的情况// Button.module.scss
// 参数化的按钮变体
@mixin button-variant($bg-color, $text-color: white) {
background-color: $bg-color;
color: $text-color;
&:hover {
background-color: darken($bg-color, 10%);
}
&:active {
background-color: darken($bg-color, 15%);
}
}
.primary {
@include button-variant(#1890ff);
}
.success {
@include button-variant(#52c41a);
}
.danger {
@include button-variant(#f5222d);
}
// 即使样式看起来相似,但因为未来可能独立修改
// 使用 mixin 更灵活
@extend 的情况// 在 CSS Modules 中,@extend 可能会有一些陷阱
// ✅ 好的使用:继承占位符
%card-base {
border-radius: 4px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.product-card {
@extend %card-base;
background: white;
}
.user-card {
@extend %card-base;
background: #f5f5f5;
}
// ❌ 避免:继承另一个模块化类名
// 这可能会导致选择器顺序问题,不建议
.special-card {
@extend .product-card; // 不推荐,可能导致意外的样式覆盖
border: 2px solid gold;
}
// styles/mixins.scss
@mixin responsive-spacing($size) {
padding: $size * 1px;
@media (max-width: 768px) {
padding: $size * 0.5px;
}
}
// components/Card/Card.module.scss
@import "../../styles/mixins";
.card {
@include responsive-spacing(16);
background: white;
// 局部样式...
}
.card-title {
font-size: 18px;
font-weight: bold;
}
// 需要复用多个样式时,使用组合而非继承
.card-featured {
composes: card; // CSS Modules 的组合特性
border: 2px solid gold;
}
在大型项目中,选择 @mixin 还是 @extend 会影响到最终 CSS 文件的大小:
@mixin:如果同一个 mixin 被多次调用且没有参数变化,会产生重复代码,增加文件体积@extend:通过合并选择器减少代码量,但过度使用可能导致选择器过于臃肿// 不推荐:大量使用无参数 mixin
@mixin hide-text {
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.logo {
@include hide-text; // 复制一份
}
.icon {
@include hide-text; // 又复制一份
}
// 推荐:使用 extend
%hide-text {
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.logo {
@extend %hide-text; // 合并选择器
}
.icon {
@extend %hide-text; // 合并选择器
}
| 选择依据 | 推荐使用 |
|---|---|
| 需要传参、动态生成 | @mixin |
| 纯静态样式复用 | @extend |
| 媒体查询内部复用 | @mixin |
| 减少代码体积 | @extend |
| 样式有独立变化的可能 | @mixin |
| 样式永远保持一致 | @extend |
在实际开发中,我的建议是:
@mixin,它更灵活,意图更明确@extend%placeholder 配合 @extend,而不是直接继承类名此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。