直接结论:用带语义键名的$spacings map定义步进值并配合@each生成工具类,比纯数字数组或硬编码更可控、可扩展、易维护;因数组无法承载语义、缺失单位且难分组,而map支持键名标识用途、值含单位参与运算,并可按margin/padding分层管理。

直接结论:用带语义键名的 $spacings map 定义步进值,配合 @each 生成工具类,比写死像素或用数字数组更可控、可扩展、易维护。
为什么不能用纯数字数组定义间距步进
常见错误是写成 $spacings: (4, 8, 12, 16) 这类数组。它会导致三个实际问题:
- 无法为每个值赋予语义(比如哪个是“紧凑”、哪个是“宽松”),后续加注释或导出设计 token 时信息丢失
- 单位缺失——SCSS 编译时不会自动补
px或rem,12和12px类型不同,后者才能安全参与calc()或被 CSS 变量消费 - 无法按需分组:比如
margin需要负值(m-n2),padding不需要,但数组没法天然区分
怎么定义语义化步进 map 才算立得住
推荐结构必须同时满足可读性、可扩展性、单位明确三项要求:
- 键名用语义字符串,如
"xs"、"sm"、"lg",避免纯数字开头("1"合法但易混淆,"01"则生成非法类名) - 值必须含单位:
0.25rem✅,4❌,"4px"❌(字符串类型无法参与 SCSS 运算) - 基础 map 按用途分层,不强行合并:
$spacings-margin和$spacings-padding分开定义,各自可独立增减键值
示例:
立即学习“前端免费学习笔记(深入)”;
$spacings-margin: ( "none": 0, "xs": 0.125rem, "sm": 0.25rem, "md": 0.5rem, "lg": 1rem, "xl": 1.5rem, "n-sm": -0.25rem, "n-md": -0.5rem );
如何用 @each 批量生成合法、无冗余的工具类
关键不是“全量生成”,而是控制输出范围和方向粒度:
- 只生成高频使用的方向组合:比如
.m-sm(全向)、.mt-sm(上)、.mx-sm(水平)就够了,避免生成.mbx-sm这类不存在的缩写 - 负边距类必须显式声明,不能靠
-#{$size}动态拼接键名——SCSS 不支持在 map key 上做表达式计算 - 用
map-get($spacings-margin, $size)显式取值,比直接遍历 map 更安全,能规避空 key 导致的编译警告
片段示意:
@each $size, $value in $spacings-margin {
.m-#{$size} { margin: $value; }
.mt-#{$size} { margin-top: $value; }
.mr-#{$size} { margin-right: $value; }
.mb-#{$size} { margin-bottom: $value; }
.ml-#{$size} { margin-left: $value; }
.mx-#{$size} { margin-left: $value; margin-right: $value; }
.my-#{$size} { margin-top: $value; margin-bottom: $value; }
}响应式步进要不要在 SCSS 里做?
不要。SCSS 编译期无法感知视口,所谓“响应式步进”只能是伪响应:
- 在
@media中重新定义$spacings再跑一遍@each,会爆炸式增长 CSS 规则数(断点 × 间距档位 × 方向) - 真正需要运行时响应的场景(如缩放适配、主题切换),应交由 CSS 变量 +
calc()实现,例如:--spacing-sm: 4px→padding: calc(var(--spacing-sm) * 1.5) - SCSS 步进 map 的唯一职责是提供静态、语义化、可复用的数值源,它是设计系统的“事实源头”,不是运行时引擎
最易被忽略的一点:所有组件中硬写的 padding: 12px 或 margin: 2rem 都是这个体系的漏洞。标准化的前提,是把每一处手动数值都收归到 map 查表逻辑里——哪怕只漏一个,整个缩放/换肤/重构就不可控。


















