SCSS中@each生成的工具类并非真通用,因其编译期固定、无法按需输出,响应式需手动嵌套@media导致体积膨胀,方向映射易错位,空值未过滤会生成无效CSS,且难以与PurgeCSS协同,维护成本高。

直接写通用工具类不如用原子化方案——SCSS 本身不支持运行时解析类名(如 mt-4),所谓“通用”往往变成硬编码、难维护、响应式失控的伪便利。
为什么@each生成的工具类不是真通用
很多人以为用 @each $key, $val in $spacing-map 批量出 .m-sm、.p-lg 就算“通用工具类”,其实只是把重复劳动交给预处理器。问题在于:
- 所有类名和规则都在编译期固定,无法按需生成(比如只用
m-2却仍得打包全部m-1到m-24) - 断点前缀(如
md:m-2)必须手动嵌套@media+@each,一漏就失效,且选择器权重易错 - 方向映射(
pt/pb/px)若用map键值对齐不当,.pt-sm可能编译成padding-top: null - 新增一个
gap-4得重写一套循环逻辑,无法复用已有结构
$spacing-types 和 $spacing-directions 映射必须严格对齐
常见翻车点:方向 map 的 key 是缩写(t),value 是字符串("top"),但拼类名时误用 value 而非 key:
@each $dir-key, $dir-val in $spacing-directions {
.p#{$dir-val}-sm { padding-#{$dir-val}: 0.5rem; } // ❌ 生成 .ptop-sm,不是 .pt-sm
}
正确做法是只用 $dir-key 拼类名,用 if 或 @if 分支处理属性值:
@each $dir-key, $dir-val in $spacing-directions {
@if $dir-val == "top" {
.p#{$dir-key}-sm { padding-top: 0.5rem; }
} @else if $dir-val == "left right" {
.p#{$dir-key}-sm {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
}
}
-
$spacing-directions必须是(t: top, x: left right)这种结构,不能是(top: t) - 类名中
#{$dir-key}是唯一安全插值点;$dir-val只用于条件判断,不进类名也不直赋属性 - 空值或
null必须提前过滤,否则.p-null-sm会静默生成无效 CSS
想支持响应式?别在 SCSS 里模拟 md:m-2
原生 SCSS 不识别冒号分隔的类名语法。所谓“支持响应式”,实际是手动展开媒体查询 + 类名组合:
@each $bp, $query in $breakpoints {
@media #{$query} {
@each $size-key, $size-val in $spacers {
.#{$bp}:m-#{$size-key} { margin: $size-val; }
}
}
}
-
$breakpoints必须是 map:(sm: "(min-width: 640px)", md: "(min-width: 768px)"),不能是 list - 生成的
md:m-2是普通类名,不是选择器嵌套结果,HTML 中必须显式写class="md:m-2" - 每个断点都会复制全部间距类,体积随断点数 × 类数量线性增长,3 个断点 × 24 个尺寸 = 72 条规则
- 无法与 PurgeCSS 配合,上线后大量未用类残留
真正省事的做法不是硬写更多 SCSS 循环,而是接受原子化 CSS 的构建逻辑:用 Tailwind 这类 PostCSS 工具生成类,SCSS 只管变量、函数、mixin 等基础能力。自己手撸的“通用工具类”,90% 场景下只是把 Tailwind 的工作量搬进 .scss 文件里,还丢了 purging、theme 扩展、IDE 支持这些关键能力。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











