应使用window.matchMedia('(prefers-color-scheme: dark)')初始化检测并监听change事件,配合document.documentElement.style.setProperty()动态设置CSS变量,同时通过data-theme属性和localStorage持久化用户选择,确保首屏渲染即生效、系统切换实时响应且无视觉闪烁。
直接用 document.documentElement.style.setProperty() 设置 CSS 变量是最简单可靠的方式,但必须配合用户偏好检测、持久化存储和 class 切换逻辑,否则会出视觉闪烁、丢失状态或覆盖系统设置等问题。
CSS 变量本身不触发媒体查询,JS 需主动监听 prefers-color-scheme 变化,不能只靠初始化时查一次。
window.matchMedia('(prefers-color-scheme: dark)') 获取当前系统偏好,.matches 返回布尔值.addEventListener('change', handler) 监听后续系统主题切换(比如 macOS 用户在控制中心实时切主题)navigator.userAgent 或 screen.colorDepth 等不可靠字段判断暗色模式直接操作 :root 的 style 属性最可控,避免污染全局或误改第三方组件的变量。
document.documentElement.style.setProperty('--bg-color', '#121212') 设置,不要用 style.cssText 全量重写(会清空其他动态样式)const themes = { light: { '--bg-color': '#fff', '--text-color': '#333' }, dark: { ... } },切换时遍历赋值setProperty 调用,再统一执行(现代浏览器对此优化较好,但大量变量时仍有差异)CSS 变量无法独立控制选择器权重或条件渲染,纯靠变量会导致部分样式无法回退(比如 img 的 filter: brightness(0.8) 在亮色下不该生效)。
立即学习“前端免费学习笔记(深入)”;
<html> 添加 class="theme-dark" 或 class="theme-light",CSS 中用 .theme-dark { --bg-color: #121212; } + .theme-dark img { filter: none; } 组合控制theme-dark theme-light)'dark' 或 'light'),读取后立即同步到 class 和变量,避免 JS 与 DOM 状态不一致根本原因是 CSS 变量更新时机与浏览器渲染流程错位,尤其在首次加载或跨设备同步时。
DOMContentLoaded 之后才读 localStorage 并设变量——应尽早(如 script 放 head 里)读取并 document.documentElement.classList.add(),让 CSS 引擎初始渲染就按目标主题走background-color: var(--bg-color); color: var(--text-color);),避免硬编码值残留:root 的变量不会穿透最易被忽略的是系统偏好监听的注册时机——如果在 React/Vue 组件挂载后才加 matchMedia 监听器,用户中途切系统主题时,页面不会响应;必须在 JS 执行早期就绑定,且确保卸载时调用 .removeEventListener 避免内存泄漏。