应预编译两套CSS变量并用@media(prefers-color-scheme:dark)控制生效,Less仅负责生成:root和媒体查询规则,组件样式须全部基于var(--xxx)实现自动适配。

如何用 prefers-color-scheme 检测系统主题并触发 Less 变量切换
Less 本身不支持运行时响应 prefers-color-scheme 媒体查询变化,它只在编译期起作用。所以不能靠“动态重编译 Less”来切换主题——那不现实。真正可行的路径是:**预编译两套 CSS 变量(light/dark),再用 CSS 媒体查询控制哪套生效**,而 Less 仅作为变量管理和生成工具。
关键在于把主题色、背景、文字等抽成 Less 变量,再通过 @media (prefers-color-scheme: dark) 封装为两组 :root CSS 自定义属性:
:root {
--bg-primary: #ffffff;
--text-primary: #333333;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #1e1e1e;
--text-primary: #e0e0e0;
}
}
Less 中可这样组织:
// variables.less
@light-bg-primary: #ffffff;
@light-text-primary: #333333;
@dark-bg-primary: #1e1e1e;
@dark-text-primary: #e0e0e0;
:root {
--bg-primary: @light-bg-primary;
--text-primary: @light-text-primary;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: @dark-bg-primary;
--text-primary: @dark-text-primary;
}
}
为什么不能直接在 Less 中用 @media 嵌套变量赋值
Less 的变量是静态解析的,@media 块内无法“重定义”顶层变量,比如下面写法无效:
立即学习“前端免费学习笔记(深入)”;
@color: red;
@media (prefers-color-scheme: dark) {
@color: blue; // ❌ 编译后不会覆盖,也不会生成条件逻辑
}
这会导致所有地方都用初始值 red,暗黑模式完全不生效。必须把主题差异落地到 CSS 自定义属性上,由浏览器运行时解析媒体查询并应用对应样式。
- Less 只负责生成干净的
:root和@media规则,不参与运行时判断 - 所有组件样式应基于
var(--bg-primary)等 CSS 变量,而非直接引用 Less 变量 - 若需 fallback(如旧浏览器不支持 CSS 变量),可用
color: @light-text-primary;作降级,但必须写在var()之前
如何让 Less 组件自动适配暗黑模式而不重复写两遍样式
只要组件使用 CSS 变量,就天然适配——不需要为 dark 写额外选择器。例如按钮:
.btn {
background-color: var(--bg-primary);
color: var(--text-primary);
border: 1px solid var(--text-primary);
}
这段代码在 light 和 dark 模式下会自动取不同值。重点在于:Less 中所有样式规则都应避免硬编码颜色/尺寸,全部走 var()。
常见踩坑点:
- 写了
.btn-dark { ... }类并手动切换——没必要,违背了“一套 CSS 适配”的初衷 - 在 Less 中用
contrast()函数算对比度然后条件输出——函数在编译期执行,无法感知用户当前系统设置 - 把
@media写在组件内部(如.btn { @media (...) { ... } })——冗余且难维护,统一收口到:root更可控
构建时要不要生成两份 CSS 文件
不需要。一份 CSS 即可,只要包含 :root + @media (prefers-color-scheme: dark) 块,现代浏览器会自动匹配。生成两份反而增加加载负担和缓存管理成本。
但要注意兼容性兜底策略:
- 若项目需支持 Safari 12.1 以下或 Firefox 67 以下,它们不支持
prefers-color-scheme,可加 JS 检测并添加class="dark"到,再用.dark .btn { ... }覆盖 - Less 中可预留
.dark覆盖区,但默认不启用,仅作 fallback 存在 - 不要依赖 JS 切换主题作为主链路——它有 FOUC 风险,且绕过了系统原生能力
最简健壮路径就是:Less 管理变量 → 输出含媒体查询的 CSS 变量 → 组件全量使用 var() → 浏览器原生响应。


















