less变量在切换主题时失效,是因为其@变量在构建时被静态替换为固定值,无法响应运行时变化;必须改用css自定义属性(--bg-primary)、data-theme控制和同步js初始化三者配合。

Less 编译出的暗黑模式变量在切换时“失效”,根本不是变量写错了,而是编译阶段就把 @color-bg-dark 替换成了固定值(比如 #121212),运行时完全无法响应主题变化——浏览器看到的 CSS 里压根没有变量,只有死值。
为什么 Less 变量在切换时根本不更新?
Less 是预处理器,所有 @ 开头的变量都在构建时(npm run build 或 webpack 编译)被静态替换。最终生成的 CSS 文件里:.card { background: #121212; } —— 它和系统偏好、data-theme、matchMedia 都无关,自然切不了。
- 你写的
@media (prefers-color-scheme: dark)规则,如果里面用的是 Less 变量,同样会被提前展开,失去响应能力 - 哪怕你在 JS 里改了
document.documentElement.dataset.theme,CSS 已经是静态的,不会重计算 - 所谓“失效”,其实是:页面先按亮色渲染 → JS 后续加类或改属性 → 浏览器重绘 → 闪一下 → 但部分样式仍卡在旧值上(因为 Less 输出的 CSS 没参与这次重绘逻辑)
必须用 CSS 自定义属性(var())替代 Less 变量
真正能响应运行时变化的,只有 CSS 自定义属性(--bg-primary),它支持继承、可被 JS 动态修改、能被媒体查询覆盖。Less 只能用来组织代码结构,不能代替它。
- 把所有主题色从
@bg-dark改成--bg-primary,并在:root中初始化::root { --bg-primary: #ffffff; } - 暗色覆盖必须写进媒体查询 +
data-theme双路径:@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --bg-primary: #121212; } }和html[data-theme="dark"] :root { --bg-primary: #121212; } - 所有样式中禁用硬编码色值,统一用
background: var(--bg-primary, #ffffff);,fallback不可省——否则变量未定义时直接崩 - Less 文件里只做“组装”:用
@bg-primary: var(--bg-primary);把 CSS 变量导入 Less 作用域,方便复用,但绝不用于最终输出
JS 初始化时机错,再对的 CSS 也会闪屏
Less 编译产物是静态 CSS,但用户看到的“失效”,90% 是因为 JS 主题初始化太晚:浏览器已用默认主题画完第一帧,才去读 localStorage 或 matchMedia,导致重绘闪白/闪黑。
- 必须把初始化脚本放在
最顶部、所有<link rel="stylesheet">之前 - 代码必须同步执行(不能加
defer或type="module"):document.documentElement.dataset.theme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); - SSR 场景(如 Next.js)要包裹
if (typeof window !== 'undefined'),否则服务端报错 - 别用
classList.add('dark'),除非 Tailwind 显式配置了darkMode: 'class';优先用dataset.theme,它更稳定、兼容伪元素和 SSR
Less 本身不处理运行时主题,它只是个构建工具。变量“失效”的本质,是你混淆了构建时逻辑和运行时逻辑。真正起作用的永远是 var(--x) + dataset.theme + 同步初始化这三者,Less 只配当个语法糖包装器,别让它背锅。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











