用$button-variants map配合@each循环可批量生成按钮类,键名须双引号字符串,值用list或嵌套map表达;&:hover和&:disabled必须在循环内定义,并对深色背景、边框状态等做守卫判断。

直接用 $button-variants Map + @each 循环就能批量产出所有按钮类,不用手写 .btn-primary、.btn-danger 等二十多个类——Map 改一处,全量重编译,颜色、边框、状态样式自动对齐。
Map 键名必须是带引号字符串,否则循环失效
常见错误是写成 primary: (#007bff, #fff),Sass 会把 primary 当作未定义变量,报错 Invalid CSS after "": expected "{", was ";"。正确写法是:
$button-variants: ( "primary": (#007bff, #fff), "success": (#28a745, #fff), "outline": (#007bff, #007bff, 2px) );
- 键名一律用双引号包裹,如
"primary",避免大小写或类型混淆 - 值用 list 表达:前两个元素固定为背景色、文字色;第三个可选(边框宽/样式),用于区分实色和描边按钮
- 别混用数字键或布尔键,
1或true作为键会导致遍历时跳项或崩溃
@each 循环里必须包含 &:hover 和 &:disabled
如果把 &:hover 写在 @each 外面,所有按钮悬停都套用同一套逻辑,颜色偏移错乱。必须让状态伪类与当前 $type 和 $props 在同一作用域内:
@each $type, $props in $button-variants {
.btn-#{$type} {
background-color: nth($props, 1);
color: nth($props, 2);
&:hover {
background-color: darken(nth($props, 1), 10%);
color: nth($props, 2);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
background-color: if(length($props) > 2, nth($props, 1), desaturate(lighten(nth($props, 1), 30%), 20%));
}
}
}
-
&:hover和&:disabled必须嵌在@each块内部,才能读取当前变体的$props - 深色背景(如
#333)慎用lighten(),容易变灰白不可读;优先对深色用darken(),浅色再用lighten() -
:disabled的背景处理建议加守卫判断:@if length($props) > 2,避免描边按钮误套背景色
边框状态需独立建模,不能靠统一 darken()
纯 darken() 算不出合理边框变化。比如 .btn-outline-primary 悬停时,边框应加深但文字不变,而禁用时边框要变淡灰。这时得把边框拆成子 map:
"outline": (
"bg": transparent,
"text": #007bff,
"border": (
"normal": 2px solid #007bff,
"hover": 2px solid #0056b3,
"disabled": 2px solid #ced4da
)
)
- 改用嵌套 map 替代 list,用
map-get($props, "border")取值 - 取子属性前务必加守卫:
@if map-has-key($props, "border"),否则map-get()返回null导致整个循环中断 - 不要在
border子 map 里混用 key 类型,"normal"和normal(无引号)会被视为不同键
真正难的不是写循环,而是让每种变体的状态逻辑自洽:描边按钮的 :hover 不该改变背景,实色按钮的 :disabled 不能只降透明度,还得调色温。这些细节得在 Map 结构里显式表达,而不是靠通用函数硬套。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











