用@for生成m-1到m-24类时,应避免硬编码单位,正确写法为@for $i from 1 through 24 { .m-#{$i} { margin: ($i * 0.125rem); } },单位需统一且参与运算,不可写$i px或混用px/rem。

用 @for 生成 m-1 到 m-24 这类间距类
直接写 24 个 .m-1 { margin: 1px; } 显然不可行,@for 是最直白的解法。关键不是“能不能循环”,而是循环变量怎么参与计算、单位怎么处理、是否要支持响应式前缀。
常见错误是把像素值硬编码进循环体,比如写成 margin: $i px; —— 这会触发 SCSS 编译报错,因为 px 不是单位操作符,必须用 #{ $i }px 或更稳妥的 ($i * 1px)。
@for $i from 1 through 24 { .m-#{$i} { margin: ($i * 1px); } }- 若需支持 rem,可提前定义基准:
$base-unit: 0.125rem;,然后写margin: ($i * $base-unit); - 避免用
px做单位参与运算(如$i + px),SCSS 会报"Invalid CSS after 'px'" - 别在循环里嵌套
@media,否则每个断点都会重复生成全部类,体积爆炸
用 @each 和 map 生成带语义的间距映射(如 m-sm)
纯数字类名(m-4)适合工具链提取,但团队协作时,m-sm、m-lg 更易读。这时用 map + @each 比 @for 更可控,也方便后续对接设计系统 token。
典型陷阱是 map 的 key 写成字符串("sm")后,在类名插值时漏掉引号,导致编译出 .m-sm 变成 .m-true 或直接报错。
- 正确写法:
$spacing-map: (sm: 0.5rem, md: 1rem, lg: 1.5rem); @each $key, $val in $spacing-map { .m-#{$key} { margin: $val; } } - 如果 map value 是表达式(如
calc(1rem - 2px)),SCSS 无法直接赋值给属性,得用#{}插值包裹 - 不要在 map 中混用单位(如
sm: 4px,md: 0.25rem),会导致最终 CSS 单位不一致,影响设计系统收敛
如何让生成的类支持响应式(如 md:m-4)
原生 Tailwind 的 md:m-4 是靠 PostCSS 插件解析类名实现的,SCSS 本身不识别这种前缀语法。真要在 SCSS 里模拟,必须手动展开断点 + 类名组合,且注意嵌套层级和选择器权重。
最容易踩的坑是用 & 嵌套时没加空格,写成 @media (min-width: 768px) { &.m-4 { ... } } —— 这实际编译为 @media {...} .parent.m-4,完全不是响应式类的意图。
- 推荐结构:
@each $bp, $query in $breakpoints { @media #{$query} { @each $i in 1 2 3 4 { .#{$bp}:m-#{$i} { margin: ($i * 0.25rem); } } } } -
$breakpoints应定义为 map:(sm: "(min-width: 640px)", md: "(min-width: 768px)") - 生成的类名如
md:m-2是普通类,不会自动绑定到父容器,需开发者手动加到 HTML 上 - 这种写法会让 CSS 体积随断点数 × 间距数线性增长,不适合超大项目;生产环境建议改用 UnoCSS 或 Tailwind 的 JIT 模式
为什么不用 @extend 替代循环生成?
有人想用 %margin-base + @extend 避免重复代码,但这是反模式。SCSS 的 @extend 本质是选择器合并,生成的 CSS 仍会把所有引用它的类名列出来,无法做到“按需输出”。而且原子类本就该独立、无依赖。
更现实的问题是:一旦你用 @extend 抽离了 m-4,后面想单独覆盖某个实例的 margin,就得用更高优先级选择器或 !important,破坏原子化“单一职责”原则。
- 原子类的核心价值是“可预测的输出”和“工具链可分析”,
@extend让类名和样式脱钩,PostCSS 工具无法识别它是否被使用 - SCSS 编译后,
@extend生成的选择器可能远超预期(比如一个%base被 50 个组件引用,CSS 里就出现 50 个逗号分隔的选择器) - 若真需要复用逻辑,应封装成 mixin:
@mixin spacing-margin($size) { margin: ($size * 0.25rem); },再在需要的地方@include spacing-margin(4)
真正难的不是写出循环,而是决定哪些值该进 map、哪些断点必须支持、以及当设计系统升级时,怎么让旧类名平滑过渡——这些没法靠代码自动生成,得靠约束和文档。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











