必须用 @each 遍历 map 生成语义化工具类,因其能同时获取键名(如"sm")和值以生成 .p-sm 等类;@for 仅适用于数字序列,@while 不适合工具类逻辑。

直接上结论:用 @each 遍历 Map 是生成语义化工具类的唯一可靠方式,@for 仅适合纯数字序列(如栅格列数),@while 几乎不该出现在工具类生成逻辑里。
为什么必须用 @each 配合 Map,而不是 List
因为工具类需要可读的键名(如 "sm"、"primary")来生成 .p-sm 或 .bg-primary 这类名字。Sass 的 @each 在遍历 List 时只给值,没有键;而 Map 才能同时提供 $key 和 $value。
- 错误写法:
$spacers: (0, 0.25rem, 0.5rem)→@each $v in $spacers只能得到0、0.25rem,无法生成.m-1中的1 - 正确写法:
$spacers: ("1": 0.25rem, "2": 0.5rem)→@each $suffix, $val in $spacers能拿到"1"和0.25rem,拼出.m-#{$suffix} - 数字键可以不加引号(
1: 0.25rem),但字符串键(如"xs")必须加,否则 Sass 会尝试计算表达式
@each 嵌套生成方向类(如 .mt-2、.pr-4)的关键细节
单层 @each 只能产出 .m-2 这种全向类;要支持方向缩写,必须嵌套两层,并严格匹配 CSS 属性名格式。
- 方向映射必须是合法 CSS 属性后缀:
$dirs: ("t": "top", "r": "right", "b": "bottom", "l": "left", "x": "left right", "y": "top bottom") - 属性拼接不能漏连字符:
margin-#{$full}✅,margin#{$full}❌(会编译成margintop) - 对
"x"和"y"这类多属性方向,要用@if分支写具体声明,不能直接插值进单个属性 - 别把方向映射写成
("t": "margin-top")——这样后面还得切字符串,徒增复杂度且易错
插值 #{$key} 在选择器里的硬性限制
#{$key} 只能在选择器中“中间或尾部”安全使用,绝不能放在开头或做字符串拼接。
- 合法:
.m-#{$suffix}、.text-#{$name}、@at-root .btn-#{$type} - 非法:
#{$prefix}-item(缺前置符号)、.#{$prefix + "-item"}(+不被支持)、.#{str-slice($name, 1)}(开头非法) - 如果
$key含破折号或数字开头(如"max-sm"、"2xl"),必须用quote($key)包裹,否则编译报错 - 从
Map中取值后若用于类名,记得unquote(map-get($map, $key)),尤其当值是转义字符(如图标 Unicode)时
生成前必须检查的三个膨胀点
一套完整工具类很容易输出几百条规则,但多数项目根本用不到全部组合。
- 方向 × 数值 × 类型(
m/p)× 断点:4 × 12 × 2 × 5 = 480 条。先砍掉非必要维度,比如先不做负边距或只支持t/r/b/l不做x/y - 断点映射的
value类型要统一:数值(768px)和字符串("768px")在@media中处理方式不同,混用会导致部分媒体查询失效 - 避免在循环里反复调用
map-get():写@each $bp, $query in $breakpoints,别写@each $bp in map-keys($breakpoints)再查表——后者性能差且易出错
最常被忽略的是 Map 键顺序不保证,别假设 map-keys($colors) 总是返回 ("primary", "secondary");如果顺序敏感(比如想让 primary 永远排第一),就得显式定义有序列表再遍历。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











