用css变量实现深色/浅色一键切换需在:root定义默认颜色,再用.dark类覆盖变量值;js仅切换的dark类,配合localstorage保存偏好,避免prefers-color-scheme局限性及页面闪动问题。

怎么用 CSS 变量实现深色/浅色一键切换
靠 :root 定义两套颜色变量,再用一个 class 控制哪套生效——不是靠 JS 换整个样式表,也不是靠媒体查询硬切,而是用 class 切换变量作用域。这样切换快、可维护、支持 localStorage 记住用户偏好。
- 把所有颜色值(
--bg、--text、--border等)写在:root里,作为默认(通常是浅色) - 再写一个
.darkclass,里面覆盖同一组变量,但赋深色值 - JS 只需给
切换darkclass,所有用var(--bg)的地方自动响应
为什么不能只靠 prefers-color-scheme
prefers-color-scheme 是浏览器告诉你的系统偏好,但它没法替代用户主动选择。比如用户系统设的是浅色,但ta就想在你网站用深色;或者系统是深色,但ta白天看网页觉得刺眼想切回浅色——这时候 prefers-color-scheme 就失效了。
- 它不响应运行时切换,只能做初始加载判断
- 无法和 localStorage 联动保存用户手动选择
- 有些旧版 Safari 对
prefers-color-scheme支持不稳定,直接依赖会丢体验
切换时页面闪一下?这是 class 加得太晚
如果 JS 在 DOM 加载完才加 dark class,而 CSS 已经按浅色渲染了一帧,就会看到“白→黑”或“黑→白”的闪动。关键不是优化 JS,而是让 HTML 初始就带对的 class。
- 服务端渲染或静态 HTML 中,根据请求头或 localStorage 值,直接给
或 - 纯前端也别等
DOMContentLoaded,改用document.documentElement.classList.add('dark')在 head 里尽早执行 - 避免在 CSS 里写
html:not(.dark) { ... }这种否定逻辑,优先用.dark覆盖,更可控
border-color 用变量后为啥边框变没了
常见错误是把 border: 1px solid var(--border) 写成 border: 1px var(--border)——漏了 solid。CSS 解析时,1px var(--border) 不合法,整条声明被忽略,border 就消失了。
立即学习“前端免费学习笔记(深入)”;
- 所有用到变量的 shorthand 属性(
border、background、box-shadow)都要确保语法完整 - 深色模式下
--border如果设成#333,在浅色背景上可能对比度太低,肉眼看不见,建议用hsl(0 0% 20%)这类可读性更强的写法 - 检查 DevTools 的 Computed 面板,确认
border-color最终计算值是否符合预期,而不是只看 Styles 里的变量引用
变量本身不难,难的是所有颜色路径都得走变量、所有边界情况都要提前测——比如 disabled 状态、focus outline、svg fill,漏一个就容易在深色下露馅。










