Sass 的 @if 仅在编译期生效,需用 $variable 控制整条规则生成;多主题用 map + @each + @mixin;禁止在 :is() 或 @if 中使用 CSS 变量或非法插值。

@if 只在编译期起作用,它不读 DOM、不认 CSS 变量、不响应用户操作——你改完 $theme 再刷新页面,样式也不会变,因为 Sass 早就不在了。
用 $variable 控制整块规则是否生成
这是最直接也最不容易出错的方式:把 @if 放在整个 CSS 规则外层,变量值决定这一整段样式进不进最终 CSS 文件。
常见错误现象:@if $enable-hover { .btn:hover { ... } } 编译后啥都没输出,或者所有主题样式全挤在一起。
- 变量必须提前声明且带
$前缀,比如$enable-hover: true;,漏写$或拼成enable-hover会报Undefined variable - 布尔判断要小心:Sass 中只有
null和false是假值,"false"(字符串)、0、空字符串都为真 - 推荐显式写
@if $enable-hover == true,比@if $enable-hover更易读、更少歧义 - 别忘了加
@else分支,否则$enable-hover: false时连基础样式都可能丢失
用 map + @each 批量生成多套主题规则
当你需要 light/dark/brand-x 多个主题共存于同一份 CSS,又不想手写十几遍 :root[data-theme="xxx"],就得靠 @each 遍历 map。
立即学习“前端免费学习笔记(深入)”;
典型翻车点:@each $theme, $map in $themes { .#{$theme} { color: map-get($map, text); } } 报 Undefined variable "$map"。
- 必须把样式逻辑封装进
@mixin,再在@each里调用,否则$map作用域不可达 - map 的 key 必须是字符串,写成
light: (text: #000)✅,不能是light: (text: #000)但 key 没引号 ❌(Sass 会当变量查) - 插值
#{$theme}只能用于选择器或属性值,不能放在:root[data-theme=$theme]这种写法里——必须加引号::root[data-theme="#{$theme}"] - 如果
map-get($map, text)返回null,说明键名不匹配,检查大小写和拼写(text≠Text)
为什么不能在 :is() 或选择器里插 Sass 变量
写 :is(.btn-#{$variant}) { ... } 看似省事,实际会生成非法 CSS,浏览器直接丢弃整条规则。
错误信息如:Expected selector 或开发者工具里该规则灰掉无效果。
-
:is()是运行时 CSS 函数,Sass 编译器不会解析它内部内容;#{$variant}被原样塞进去,变成:is(.btn-"primary"),引号是非法字符 - 所有选择器拼接必须在 Sass 层完成,且不嵌套在 CSS 函数中:正确写法是
.btn-#{$variant} { ... } - 想实现“多个类名共用一套样式”,用
@extend或抽公共@mixin,别指望:is()帮你绕过编译限制 - 同理,
@if里也不能出现var(--theme),Sass 根本不认识这个语法,直接报Invalid CSS after "if"
容易被忽略的调试和维护细节
半年后回来看自己写的 @if $mode == "compact",却不知道 $mode 是从哪传进来的、有没有默认值、哪些组件依赖它——这种问题比语法错误更难查。
- 每个关键变量都加
!default,比如$theme: "light" !default;,避免未声明就报错 - 在
@if前加@debug "theme is:", $theme;,一眼看出变量值和类型 - 不要把逻辑分散在多个文件里:顶层配置(
_config.scss)、主题 map(_themes.scss)、条件规则(_buttons.scss)之间要有清晰引用链 - CI 构建时加
--no-source-map和--trace,能让报错定位到具体行,而不是笼统的 “Invalid CSS”


















