less变量仅编译时生效,无法运行时切换;正确做法是用css自定义属性(如--primary-color)承接动态性,less仅封装var(--xxx)引用,js通过切换body类名触发css变量更新。

Less 本身不支持运行时切换主题——它在构建阶段就完成了变量求值和样式生成。所谓“无缝切换”,本质是让 CSS 变量(var(--primary-color))承接动态性,而 Less 仅负责把变量声明和引用写得可维护、不重复。
为什么不能直接用 @primary-color 切换主题
Less 变量是编译期静态值。写成 .dark { @primary-color: #1e1e1e; } 不会生效:这个 @primary-color 在编译时就被替换成固定颜色了,不会随 class 存在与否而变化。浏览器只看到最终的 CSS,根本不知道 Less 里有过什么变量。
- 所有基于
@xxx的赋值、计算(如lighten(@primary-color, 10%))都在编译时完成 -
.dark .btn这类选择器能生效,但前提是它的样式规则里用的是 CSS 变量,不是 Less 变量 - 试图用
@import动态加载不同 theme 文件也无效——导入发生在编译前,不是运行时
正确做法:用 :root + body.dark 控制 CSS 变量
把主题色映射到 CSS 自定义属性,再用 Less 封装引用层。这样 JS 切换 body 类名时,CSS 变量自动更新,所有 var(--bg-color) 都响应变化。
- 在
theme.less里定义两套 CSS 变量:
:root {
--bg-color: #fff;
--text-color: #333;
--primary-color: #1890ff;
}
body.dark {
--bg-color: #141414;
--text-color: #f0f0f0;
--primary-color: #177ddc;
}
- 在其他 Less 文件中统一用
@bg-color: var(--bg-color);引用,而不是硬写#fff - 确保所有组件样式都基于这些
@xxx: var(--xxx)变量编写,比如background: @bg-color; - 避免在
:root外再写.dark { --bg-color: ... }——这会导致作用域混乱,优先级难控
JS 切换时必须操作 document.body 而非 document.documentElement
很多人习惯给 html 加 class,但如果你的 CSS 规则是 body.dark { --xxx: ... },那 class 必须加在 body 上才生效。否则变量不会被覆盖,主题不变。
- 正确:
document.body.classList.toggle('dark'); - 错误:
document.documentElement.classList.toggle('dark');(除非你把规则写成html.dark) - 记得同步 localStorage 并在页面加载时读取,否则刷新后退回到默认主题
- 如果用了 Vue/React,别在组件 mounted 里才加 class——要尽早(比如在
标签内加初始 class),避免闪屏
容易被忽略的兼容与性能点
CSS 变量方案在 Chrome/Firefox/Safari(2016+)完全可用,但 IE11 及更早版本不支持。若需兼容,就得构建多套 CSS 文件并切换 <link> 标签——这时 Less 的作用只是生成多份 CSS,不再参与运行时逻辑。
- 频繁调用
element.style.setProperty('--color', ...)会触发重排,适合一次性批量设置;主题切换推荐用 class 切换 - 不要在 Less 中用
@import按条件引入不同变量文件——Webpack 的less-loader的modifyVars才是构建时注入的正解 - 暗色模式下
box-shadow常需更浅的透明度,别只靠一个--shadow-color变量,用.theme-aware-shadow()Mixin 封装更稳妥
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











