SCSS嵌套Map需手动分层遍历,@each不支持自动递归;键名必须为带引号字符串,禁止动态key;推荐扁平化设计以避免map-merge覆盖问题。

嵌套 Map 必须手动展开,@each 不会自动递归
SCSS 的 @each 只能遍历一层 map,遇到值是 map 的情况(比如 "primary": ("bg": #007bff, "text": #fff)),它不会继续往下钻。你看到的“没生成 hover 样式”或“border 没出来”,90% 是因为只遍历了外层键,没对内层再写一次 @each。
正确做法是明确分层:外层遍历主题/组件名,内层遍历该主题下的属性键值对。不能指望一个循环吃掉所有层级。
- 错误示例:
@each $name, $props in $button-variants { background-color: map-get($props, "bg"); }—— 这行能跑,但border-color、hover-bg等其他键全被忽略 - 正确结构:先
@each $name, $props in $button-variants,再在内部加@each $prop-key, $prop-val in $props,并用@if $prop-key == "hover-bg"分支控制逻辑 - 必须加守卫:
@if map-has-key($props, "hover-bg"),否则map-get($props, "hover-bg")返回null,编译不报错但 CSS 里啥也不输出
键名必须是字符串字面量,变量或未引号 key 全报错
嵌套 map 里任何 key 只要不是带引号的字符串(如 "bg"),Sass 就当它是变量名去查——而这个变量几乎肯定不存在,结果就是 Undefined variable "bg" 或 map-get() argument must be a map。
尤其注意:map 的 key 不支持动态拼接,$key: "bg"; map-get($props, $key) 是非法的,Sass 不允许运行时求值作为 key。
- ✅ 正确:
"bg": #007bff、"hover-bg": darken(#007bff, 10%) - ❌ 错误:
bg: #007bff(缺引号)、$bg-key: "bg"; #{$bg-key}: #007bff(动态 key 不合法) - ⚠️ 隐患:大小写敏感,
"BG"和"bg"是两个 key,map-get($props, "bg")查不到"BG"
生成多级类名时,插值顺序决定 CSS 可读性与维护成本
像 .btn-primary-hover 或 .card-dark-header 这种类名,本质是两层语义拼接。如果把拼接逻辑写死在选择器里(如 .btn-#{$name}-hover),后期想加前缀或换分隔符就得改所有地方。
更稳的方式是把命名规则收口到函数里,比如封装 theme-class("button", $name, "hover"),内部统一处理连字符、大小写、命名空间。
- 避免嵌套过深:三层以上(如
button → primary → hover → disabled)建议拆成独立 map,而不是"primary": ("hover": ("disabled": ...)) - 方向类需额外映射:生成
.mt-2时,"t"要对应"top",这个映射关系必须显式定义,不能靠猜测 - 响应式类别放外层:要加
md:mt-4,就先@each $breakpoint, $width in $grid-breakpoints,再嵌套间距循环,否则每个类都套一遍@media,CSS 体积翻倍
map-merge 无法穿透嵌套,深度合并得自己写函数
map-merge($a, $b) 遇到同 key 的嵌套 map,直接整个替换,不会比对子键。比如 $a: ("dark": ("bg": #111, "text": #fff)) 和 $b: ("dark": ("text": #e2e8f0)) 合并后,"bg" 就丢了——这不是 bug,是设计如此。
真需要保留原嵌套结构里的未覆盖字段,必须手写递归函数,用 type-of() 判断值类型,是 map 就再调一次自身。但绝大多数项目没必要:把颜色、边框、圆角这些拆成扁平的独立 map($button-colors、$button-borders)更清晰,也避免合并陷阱。
- ✅ 推荐:
$button-states: ("default": #007bff, "hover": #0056b3, "disabled": #6c757d)—— 单层,可安全map-merge - ❌ 避免:
$button-themes: ("primary": ("default": ..., "hover": ...))—— 合并时容易丢配置 - ⚠️ 注意:
map-merge必须在所有依赖它的样式文件 之前 执行,否则 Bootstrap 等框架已用旧 map 初始化完毕,合并等于白做
嵌套 map 的价值在于语义分组,不是为了堆深度。真正难的从来不是怎么写循环,而是决定哪些东西该塞进同一层 map —— 比如把 "icon-home" 和 "bg" 放一起,就暗示它们属于同一主题维度;一旦混进 "border-radius",语义就断了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











