最轻量可靠的方式是直接用@media (prefers-color-scheme: dark),因Less仅在构建时展开变量,无法响应系统主题实时切换;应将颜色变量抽为函数式定义,分别注入媒体查询内,避免顶层包裹或遗漏默认样式。

直接用 @media (prefers-color-scheme: dark) 是最轻量、最可靠的方式,不需要 JS 控制或重复编译多套变量——Less 本身不感知系统主题变化,它只是预处理器。
为什么不能靠 Less 变量动态切换深色模式
Less 在构建时就已将变量展开为静态 CSS,@dark-bg 或 @light-text 这类变量一旦编译完成就固化了,无法响应用户系统设置的实时切换。试图用 .dark-mode { ... } 类名包裹再靠 JS 切换,反而增加冗余逻辑和维护成本。
- Less 编译发生在构建阶段,不是运行时
- 所有变量、混合(
.mixin())、嵌套都会被扁平化输出 - 若强行用 JS 注入 class 并写两套样式,会放大 CSS 体积且易遗漏状态同步
正确做法:用原生媒体查询 + Less 组织颜色逻辑
把颜色定义抽成可复用的函数式变量(非运行时变量),再用 @media 分别注入,既保持 Less 的结构优势,又兼容浏览器原生能力。
@light-bg: #ffffff;
@light-text: #333333;
@dark-bg: #1a1a1a;
@dark-text: #e6e6e6;
// 基础组件样式(不指定颜色)
.card {
padding: 1rem;
border-radius: 4px;
// 深色模式下覆盖
@media (prefers-color-scheme: dark) {
background-color: @dark-bg;
color: @dark-text;
}
// 浅色模式默认(也可显式写 @media (prefers-color-scheme: light))
background-color: @light-bg;
color: @light-text;
}
- 避免在
@media外直接写background-color: @dark-bg—— 这会让浅色模式也继承暗色值 - 推荐把
@media放在具体选择器内部,而非顶层包裹,防止规则被意外覆盖 - 如需复用配色逻辑,可用
.color-theme() { ... }混合,但调用时仍需分别塞进两个媒体查询里
需要 JS 强干预时的边界情况
当产品要求「手动开关深色模式」(绕过系统偏好),才需 JS 控制 class 并配合 Less 输出双主题规则。此时关键不是让 Less 动态变,而是确保两套规则互斥且优先级明确。
立即学习“前端免费学习笔记(深入)”;
- 给
<html>添加data-theme="dark",而非.dark-mode类——更利于 CSS 优先级控制 - Less 中写:
html[data-theme="dark"] .card { background-color: @dark-bg; } - 必须同时写
html:not([data-theme="dark"]) .card或依赖默认浅色样式,否则无主题属性时会失效 - 注意:这种方案会禁用系统自动切换,除非 JS 主动监听
matchMedia("(prefers-color-scheme: dark)")并同步 data-theme
真正容易被忽略的是媒体查询的嵌套位置和默认样式的落点——很多人把所有颜色都塞进 @media 里,结果浅色模式完全没样式;或者把 @media 写在最外层导致选择器重复、 specificity 不一致。Less 只负责组织,生效靠浏览器,这点不能颠倒。


















