必须用#{}做类名插值当类名的一部分来自变量、函数返回值或计算结果且编译时才能确定,如循环索引、map的key、断点名等;直接写.foo-#{$size}会被当作字面量,而.foo-#{ $size }才展开值,且前后加空格更安全。

什么时候必须用 #{} 做类名插值
当类名的一部分来自变量、函数返回值或计算结果,且这个部分在编译时才能确定(比如循环中的索引、map的key、响应式断点名),就必须用 #{} 。直接写 .foo-#{$size} 会被Sass当作字面量处理,而 .foo-#{ $size } 才会真正展开变量值。
常见错误是漏掉空格:写成 .foo-#{$size} 看似没问题,但若 $size 是 "lg" ,结果是 .foo-lg ;可一旦 $size 是 "2xl" ,没空格反而容易和前缀连成 .foo2xl ——这不是拼错,是Sass把 foo 和 #{ $size } 当作同一标识符前缀了。所以习惯上在 #{} 前后各留一个空格更安全。
- 只在类名、属性值、选择器中需要动态文本的地方用
#{},普通CSS规则里不用 -
#{}不能嵌套,比如#{ #{ $var } }会报错 - 如果插值内容含特殊字符(如
/、.),需确保它本身是合法CSS标识符,否则生成的类名无效
@each 循环中用 #{} 批量生成响应式类
这是最典型的使用场景:遍历断点map,为每个断点生成 .text-xs@sm 、.text-sm@md 这类类名。关键在于把断点名作为插值一部分,而不是硬编码。
$breakpoints: (
sm: 640px,
md: 768px,
lg: 1024px
);
@each $name, $width in $breakpoints {
@media (min-width: $width) {
.text-xs#{"@#{$name}"} {
font-size: 0.75rem;
}
.text-sm#{"@#{$name}"} {
font-size: 0.875rem;
}
}
}
注意这里用了双层插值:#{"@#{$name}"} 。外层 #{} 表示字符串拼接,内层 #{$name} 展开变量。如果只写 @#{$name} ,Sass会尝试解析为伪类或属性,报错。
- 不要在
@media外直接写带#{}的顶层类名,否则生成的CSS选择器可能无效(如.foo#{ $x }编译后是.foo后跟未闭合的括号) - 若断点名含破折号(如
"max-sm"),插值后类名会是.text-xs@max-sm,浏览器能识别,但部分CSS工具链可能警告
用 #{} 拼接函数返回值时的类型陷阱
Sass函数(比如 str-slice() 、percentage() )返回值不全是字符串。如果直接插进类名,可能出错:
比如想截取颜色变量名后三位做类名后缀:$color-name: "primary" ,写成 .bg-#{ str-slice($color-name, -3) } 看似合理,但 str-slice 返回的是字符串,没问题;而如果误用 percentage(0.5) ,它返回的是带单位的 50% ,插进类名就变成 .bg-50% —— 这不是合法CSS类名。
- 插值前用
type-of()检查返回值类型,非字符串时先转:#{ "" + percentage(0.5) }或#{'' + percentage(0.5)} - 避免对
map-get()结果直接插值,除非确认值是字符串;否则加一层inspect()或"" +转换 -
#{}不会自动去除引号,#{ "foo" }结果是foo(无引号),但#{ 'foo' }也一样——单双引号在插值中无区别
为什么有时 #{} 不生效,编译后还是原样
最常见原因是插值位置不对:Sass只在选择器、属性值、@规则参数中解析 #{} ,如果写在注释里、纯文本字符串里,或者被包裹在引号中(如 "class-#{$x}" ),它不会执行。
另一个隐蔽问题是作用域:变量在 @each 或 @for 块内定义,但在块外插值,此时变量未定义,Sass可能静默忽略或报错,导致类名为空或异常。
- 检查浏览器开发者工具里生成的CSS,确认类名是否真的被展开;没展开就说明插值没进入编译流程
- 用
@debug #{$var}在插值前输出变量值,确认它不为空、不是null或undefined - 避免在嵌套过深的选择器里多层插值,每多一层
#{}都增加解析失败风险
插值看着简单,但变量来源、作用域、类型、上下文缺一不可。漏掉任何一个,生成的类名就可能消失、错位,或者变成非法字符——这些都不会在Sass编译时报错,只能靠生成后的CSS反查。










