SCSS的@if仅在编译期生效,依据Sass变量(如$theme)生成固定CSS,无法响应运行时data-theme或CSS变量切换;实现主题切换需结合CSS自定义属性、[data-theme]选择器与JS控制。

SCSS的@if只在编译期生效,不能响应运行时切换
直接说结论:@if 判断的是 Sass 变量(如 $theme: dark),不是浏览器里的 data-theme 或 CSS 变量。它在构建时就跑完、生成固定 CSS,之后 JS 改 document.documentElement.setAttribute('data-theme', 'light') 完全不影响已编译好的样式。
常见翻车现场:@if $theme == 'dark' { .btn { color: white; } } 看起来像能切换,但只要 $theme 是硬编码或通过 --define=theme=dark 传入,那最终 CSS 里就只有暗色规则——或者只有亮色,取决于你编译时用的值。
-
@if能安全依赖的只有 Sass 本体变量、type-of()、lightness()这类编译期可求值的东西 -
var(--theme)或getComputedStyle()在@if里根本不可用,Sass 解析器不认识,会报Invalid CSS after "if": expected expression - 想让页面“点一下变主题”,必须靠 CSS 自定义属性 +
[data-theme]选择器 + JS 控制,@if只负责把不同主题的 CSS 规则“提前写进文件”
用 @each + map 实现多主题 CSS 输出
真正可维护的做法是把主题当数据对象存进 SCSS map,再用 @each 遍历生成对应选择器块,而不是手写一堆 [data-theme="dark"]。
示例结构:
立即学习“前端免费学习笔记(深入)”;
$themes: (
light: (bg: #fff, text: #1e293b, primary: #4285f4),
dark: (bg: #0f172a, text: #f1f5f9, primary: #79bbff)
);
@each $theme-name, $theme-map in $themes {
[data-theme="#{$theme-name}"] {
--bg-color: #{map-get($theme-map, bg)};
--text-color: #{map-get($theme-map, text)};
--primary-color: #{map-get($theme-map, primary)};
}
}
- 所有主题的 key(
bg、text)必须完全一致,否则map-get($theme-map, text)可能返回null - 生成的是 CSS 变量赋值,不是直接写死颜色——这样组件才能用
color: var(--text-color)响应切换 - 别漏掉默认
:root值,否则首次渲染时var(--text-color)没 fallback,文字可能透明或继承错色
mixins 中怎么安全读取当前主题值
在 mixin 里不能直接用 $theme-map,因为 @each 的作用域是局部的。必须用 !global 提升,或封装成函数。
推荐写法:
@function themed($key) {
@return map-get($theme-map, $key);
}
@mixin themeify {
@each $theme-name, $theme-map in $themes {
$theme-map: $theme-map !global;
[data-theme="#{$theme-name}"] & {
@content;
}
}
}
// 使用
.button {
@include themeify {
background-color: themed(primary);
color: themed(text);
}
}
-
$theme-map: $theme-map !global是关键,否则themed()函数里读不到当前循环的主题 map -
&保留父选择器上下文,适合嵌套组件复用 - 避免在 mixin 内部再套
@if判断主题名——冗余且易出错,@each已经按主题分开了
为什么不能只靠 @if + 单个变量控制主题
有人试图这样写:$theme: 'dark'; @if $theme == 'dark' { ... },看似简洁,但实际带来三个硬伤:
- 新增主题要改所有
@if块,漏一处就断链;而 map +@each新增主题只需往 map 里加一项 - 无法生成多套独立规则:你只能输出“暗色版”或“亮色版”,不能同时存在并靠
[data-theme]切换 - 主题色计算(比如根据主色自动算出可读文本色)必须用
lightness()这类函数,而它们只能作用于 Sass 变量,不能作用于运行时 CSS 变量
真正需要 @if 的地方,其实是编译期逻辑,比如:@if lightness($primary) ——这种才发挥 <code>@if 的优势。


















