在现代化前端开发中,为用户提供浅色与深色两种界面已成为基础体验需求。借助JavaScript控制CSS变量,我们可以用极少的代码完成整套主题切换逻辑,而不必为每个颜色重复编写样式规则。

一、核心原理:CSS变量与JavaScript的配合
CSS自定义属性(俗称CSS变量)允许我们在样式表中声明可复用的值,例如背景色、文字色、边框色等。通过在根元素:root或html上定义这些变量,页面中任意使用var()的地方都会随变量变化而自动更新。JavaScript要做的只是修改这些变量的值,或者切换一个标记属性让不同的CSS块生效。
这种方式的优势在于解耦:视觉规范集中在变量声明处,组件只消费变量。当我们需要新增一套主题,例如护眼模式,只要补充一组变量映射即可,业务逻辑完全不用动。相比早期用JavaScript遍历DOM改style的做法,性能与可维护性都更好。
1.1 使用data-theme属性驱动
最常见且清晰的做法是给html元素设置data-theme="dark"或data-theme="light",然后在CSS中针对不同的属性值写变量集合。JavaScript仅需切换该属性,浏览器便会重新计算样式。
下面是一段基础样式声明,展示了如何为两种主题定义变量:
:root {
--bg: #ffffff;
--text: #333333;
--primary: #0066ff;
}
html[data-theme='dark'] {
--bg: #1a1a1a;
--text: #e6e6e6;
--primary: #4da3ff;
}
body {
background-color: var(--bg);
color: var(--text);
}
a {
color: var(--primary);
}
1.2 使用JavaScript直接改CSS变量
如果不想依赖属性选择器,也可以用document.documentElement.style.setProperty直接覆盖根变量。这种方法更灵活,适合主题值来自接口或用户调色板的场景。
示例代码如下:
function setTheme(bg, text, primary) {
const root = document.documentElement;
root.style.setProperty('--bg', bg);
root.style.setProperty('--text', text);
root.style.setProperty('--primary', primary);
}
// 切换到深色
setTheme('#1a1a1a', '#e6e6e6', '#4da3ff');
二、完整可运行的主题切换实现
下面给出一个包含按钮切换、本地存储与系统偏好读取的完整示例。它能在用户点击按钮时切换主题,并把选择记入localStorage,下次访问自动应用,同时首次加载会参考系统的深色模式设置。
HTML部分只需一个按钮和若干使用变量的元素:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>主题切换示例</title>
<style>
:root { --bg: #fff; --text: #333; --primary: #0066ff; }
html[data-theme='dark'] { --bg: #1a1a1a; --text: #e6e6e6; --primary: #4da3ff; }
body { background: var(--bg); color: var(--text); font-family: sans-serif; padding: 20px; }
button { background: var(--primary); color: #fff; border: none; padding: 8px 16px; cursor: pointer; }
</style>
</head>
<body>
<h1>欢迎访问</h1>
<p>这是一个支持主题切换的页面。</p>
<button id="toggleBtn">切换主题</button>
<script src="theme.js"></script>
</body>
</html>
对应的JavaScript逻辑放在theme.js中:
(function () {
const root = document.documentElement;
const btn = document.getElementById('toggleBtn');
const saved = localStorage.getItem('theme');
const sysDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
// 初始化主题
if (saved) {
root.setAttribute('data-theme', saved);
} else if (sysDark) {
root.setAttribute('data-theme', 'dark');
}
btn.addEventListener('click', function () {
const current = root.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
});
})();
2.1 避免页面闪烁问题
如果等JavaScript加载完才设置主题,用户在浅色背景下会先看到白屏再跳到深色,体验较差。解决办法是在head里内联一小段脚本,在DOM构建前就决定data-theme。
例如把下面代码直接写在head中:
<script>
(function () {
var t = localStorage.getItem('theme');
if (!t) {
t = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
document.documentElement.setAttribute('data-theme', t);
})();
</script>
三、方案对比与注意事项
使用CSS变量加data-theme的方式,比用类名切换或逐条改style更利于统一管理。下表列出几种常见方案的差异:
| 方案 | 维护成本 | 性能 | 适用场景 |
|---|---|---|---|
| 遍历DOM改style | 高 | 差 | 极老项目兼容 |
| 类名切换整套CSS | 中 | 好 | 主题少且固定 |
| CSS变量+data-theme | 低 | 优 | 多主题、动态色 |
在实践里还要注意,部分旧版浏览器不支持CSS变量,若必须兼容应提供降级样式。另外,切换主题时若页面含有canvas或第三方组件,它们可能不会自动响应变量,需要手动重绘或传入对应颜色值。
总体而言,JavaScript结合CSS变量是实现颜色主题切换最简洁且易扩展的做法,既能满足用户偏好记忆,也能无缝对接系统级深色模式设置。
JavaScript颜色主题切换CSS变量修改时间:2026-07-31 15:00:30