sass中选择器开头不能直接插值,必须确保插值位于合法标识符位置;安全做法是嵌套中用&+@at-root或顶层@each/@for循环;含破折号/数字的后缀需quote()包裹;map-get返回值须unquote()后使用。

直接用 #{$var} 拼类名会报错:Invalid CSS after “.foo-”: expected class name
很多人写 .foo-#{$suffix} 想生成 .foo-header,但 Sass 编译直接报错。原因不是语法写错,而是 Sass 解析器要求选择器开头必须是合法标识符(字母、下划线或$),而#{$suffix}在解析阶段尚未展开,被当作“空起始”拒绝。
真正能用的只有两种安全路径:
- 把插值放在已有选择器内部,用
&引用父级 +@at-root提升作用域(比如嵌套里生成顶层类) - 用
@each或@for在顶层循环,让插值始终处于可预测上下文中
str-slice() 和 str-replace() 能处理类名字符串,但不能用于选择器开头
这类函数只操作已存在的字符串值,比如从变量 $name: "primary" 中截取后两位:.bg-#{str-slice($name, -2)} → .bg-ry。它可行,因为插值发生在点号.之后、合法标识符位置。
但以下写法全无效:
-
.#{str-slice($name, 1, 3)}-btn——#{...}出现在选择器最前面 -
.btn-#{str-replace("large", "large", "lg")}—— 看似合理,但str-replace返回字符串,Sass 不允许它作为选择器首段 -
.#{"btn"}-#{"lg"}—— 双重插值仍不解决“开头非法”问题
带破折号或数字开头的类名后缀要加引号包裹再插值
如果后缀来自 map 或 list,且含破折号(如 "max-sm")或数字开头(如 "2xl"),直接插值会触发 Sass 解析异常。正确做法是先用 quote() 包一层:
$sizes: ("sm": 0.75rem, "max-sm": 0.625rem, "2xl": 2rem);
@each $key, $val in $sizes {
.text-#{quote($key)} {
font-size: $val;
}
}
编译后得到 .text-"sm"、.text-"max-sm" 这种带引号类名——CSS 允许,浏览器能匹配,但部分 Lint 工具会警告。若不想引号,就别让变量值含非法字符,改用下划线或纯字母前缀。
用 map-get() 查找图标名拼类时,别漏掉 unquote()
常见需求:根据图标名生成 .icon-home、.icon-user。若图标名存在 map 里:$icons: ("home": \e901, "user": \e902),那 .icon-#{map-get($icons, "home")} 会失败——因为 map-get 返回的是转义字符 token,不是字符串。
必须显式转成字符串再解引号:
- 错误:
.icon-#{map-get($icons, "home")}→ 编译出.icon-\e901(非法选择器) - 正确:
.icon-#{unquote(map-get($icons, "home"))}→.icon-e901(合法)
注意:unquote() 只去掉引号,不改变内容;map-get 的 key 必须和调用时完全一致(大小写、连字符),否则返回 null,插值后变成空类名 .icon-,极难排查。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











