纯 sass 无法读取用户系统深色偏好,因 prefers-color-scheme 是运行时 css 媒体查询,@if 仅在构建时静态执行;可行方案是用 sass mixin 生成含媒体查询的 css 变量规则,如 @mixin theme-var($name, $light, $dark)。

纯 Sass 无法在编译时读取用户系统深色偏好,prefers-color-scheme 是运行时 CSS 媒体查询,不是 Sass 的 @if 条件;真正可行的是用 Sass 生成带媒体查询的 CSS 变量规则,而非“让 Sass 判断主题”。
为什么 @if $theme == dark 在 Sass 中根本无效
Sass 编译发生在构建阶段(比如你执行 npm run build),此时浏览器还没打开,更不知道用户的系统设置。写 @if (prefers-color-scheme: dark) 会直接报错——Sass 根本不识别这个语法。所有“根据系统偏好分支编译”的想法,都混淆了编译时和运行时边界。
真正该做的,是让 Sass 输出符合规范的 CSS,把判断权完全交给浏览器:
-
prefers-color-scheme必须出现在最终生成的 CSS 文件里,作为@media规则 - Sass 只负责批量生成两套变量声明,避免手写重复
- 所有颜色值必须显式定义,不能依赖 Sass 函数在运行时“自动变暗”
用 @mixin 封装双模式变量声明
手动写 :root { --color-bg: #fff; } @media (prefers-color-scheme: dark) { :root { --color-bg: #121212; } } 很容易漏、难维护。Sass 的 @mixin 能帮你一次生成完整结构:
@mixin theme-var($name, $light, $dark) {
#{$name}: #{$light};
@media (prefers-color-scheme: dark) {
#{$name}: #{$dark};
}
}
:root {
@include theme-var(--bg-base, #ffffff, #121212);
@include theme-var(--text-primary, #333333, #e0e0e0);
}
注意:#{$name} 是 Sass 插值语法,生成的是 --bg-base 这样的合法自定义属性名;@media 块必须直接写在 :root 内部,不能嵌套在其他媒体查询中(旧版 Safari 不认)。
lighten() 和 darken() 在深色模式下为什么危险
这两个函数只做 HSL 明度加减,不感知背景语义。例如 lighten(#121212, 20%) 会得到灰蒙蒙的 #4a4a4a,在深色背景下文字对比度暴跌,甚至不可读;而 lighten(#ffffff, 20%) 直接溢出为白色,毫无变化。
更稳妥的做法是预设两套值,或用 color.contrast-color()(来自 sass:color 模块):
-
color.contrast-color($brand-blue)返回#000或#fff,取决于哪个在当前背景上对比度更高 - 但它只输出黑白,若需灰阶边框,得配合
lightness()手动分段:if lightness($color) > 50% { darken($color, 15%) } else { lighten($color, 15%) } - 别试图用一个 Sass 表达式“适配所有背景”,而是为每个语义角色(如
--border-divider、--text-secondary)单独定义浅/深值
如何避免页面加载时闪白屏
浏览器先按 :root 默认值渲染(比如 --bg-base: #fff),等 @media (prefers-color-scheme: dark) 匹配后才重绘,导致肉眼可见的“白→黑”闪烁,尤其在 iOS Safari 上明显。
解决方法不是靠 Sass,而是轻量 JS 同步检测并提前注入 class:
- 在
里内联一小段 JS:if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) document.documentElement.setAttribute('data-theme', 'dark'); - CSS 中同时写两套规则:
[data-theme="dark"] .card { background: var(--bg-base); }(防闪) +@media (prefers-color-scheme: dark) .card { background: var(--bg-base); }(保语义) - 所有
var(--xxx)都要加 fallback:background: var(--bg-base, #ffffff);,防止变量未定义时样式崩塌
最关键的细节:CSS 变量的值不是“动态计算”的,它只是按层叠顺序被覆盖;媒体查询里的声明不会“回写”到初始 :root,所以 fallback 和双重声明缺一不可。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











