夜间模式切换的核心逻辑是动态修改document.body的class并配合CSS变量响应,性能好、易维护;需用localStorage存状态,页面加载时优先按存储值初始化,而非直接读系统偏好。

夜间模式切换的核心逻辑是什么
本质是动态修改 document.body 的 class,并配合 CSS 变量或预设样式表控制颜色。不是靠 JS 改每个元素颜色,而是用 CSS 层级和变量批量响应——这样性能好、易维护、可持久化。
关键点:prefers-color-scheme 只能读取系统偏好,不能主动设置;所以必须自己存状态(localStorage),并在页面加载时优先按存储值初始化,而非直接读系统。
如何用 class 切换 + CSS 变量实现主题切换
推荐用一个 class(比如 dark)挂载在 <body> 上,所有夜间样式通过 body.dark { --bg: #121212; --text: #e0e0e0; } 定义。这样避免重复写选择器,也方便后续扩展。
- 在
<style>或 CSS 文件中定义两套变量:默认(light)和body.dark下的覆盖值 - 按钮点击时执行:
document.body.classList.toggle('dark') - 立即同步到
localStorage:localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light') - 页面加载时读取:
const saved = localStorage.getItem('theme');,然后手动加 class 或移除
为什么不能只靠 matchMedia 监听系统主题
matchMedia('(prefers-color-scheme: dark)') 能监听系统变化,但用户主动点按钮切换后,系统主题没变,监听器不会触发——导致 UI 和用户操作脱节。它只适合「默认跟随系统」的兜底逻辑,不能替代手动控制。
立即学习“前端免费学习笔记(深入)”;
正确做法是:加载时先查 localStorage,没值再 fallback 到 matchMedia;之后所有切换都走 JS + storage,matchMedia 仅作初始化参考。
按钮点击后页面闪一下?这是 CSS 加载顺序问题
如果夜间样式写在外部 CSS 文件里,且未提前加载,切换 class 后浏览器要重绘,可能短暂显示默认色再变暗——肉眼可见闪烁。
- 把主题变量定义放在
<head>内联<style>中(哪怕只是基础变量声明) - 确保
body在 DOM ready 前就已有初始 class(服务端渲染或 JS 同步设置) - 避免在
DOMContentLoaded之后才读取localStorage并加 class——这时 body 已渲染完毕,必然闪
最稳的方式:HTML 的 <body> 标签上直接带 class,由后端或构建时注入;前端 JS 只负责更新和同步 storage。



















