window.matchMedia('(prefers-color-scheme: dark)').matches可直接判断当前系统是否启用暗黑模式,但需配合addEventListener('change', handler)监听切换事件,并在SPA卸载时移除监听;SSR中须加typeof window !== 'undefined'守卫,且用户手动选择主题时应优先级高于系统偏好,通过localStorage持久化避免刷新丢失。

直接用 window.matchMedia 检测,但不监听 change 就等于没做响应式——系统切了主题,页面毫无反应。
怎么用 window.matchMedia 判断当前是否暗黑模式
它返回一个 MediaQueryList 对象,核心就看 matches 属性:
-
window.matchMedia('(prefers-color-scheme: dark)').matches是布尔值,true表示系统当前启用了暗黑模式 - 这个值只在页面加载、窗口重排或系统主题变更后重计算,不是实时轮询出来的
- 别写成
window.matchMedia('dark')或漏掉括号和引号,否则返回null或匹配失败 - SSR(服务端渲染)环境里,
window不存在,必须加typeof window !== 'undefined'守卫
为什么写了 matchMedia 却不响应系统切换
因为 matchMedia 本身不自动监听,你得手动绑定事件——而且必须用 addEventListener,不是赋值 onchange:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 正确写法:
const mq = window.matchMedia('(prefers-color-scheme: dark)'); mq.addEventListener('change', e => { console.log(e.matches); }); - 旧版 Safari 可能需要兼容
addListener,但现代项目建议统一用标准事件 API - 匿名函数无法被移除,后续内存泄漏风险高;务必保存 handler 引用,比如
const handler = e => {...}; mq.addEventListener('change', handler); - 单页应用中,组件卸载时忘了
mq.removeEventListener('change', handler),会导致多次重复监听
data-theme 和 :root 变量怎么配合才不翻车
媒体查询只负责“告诉 CSS 什么时候该换变量”,但变量定义顺序、作用域和覆盖逻辑错一点,暗色模式就失效:
- 默认变量必须写在
:root顶层,暗色覆盖必须用@media (prefers-color-scheme: dark) { :root { ... } },反过来写会导致暗色下var(--bg)解析为unset - 不要在组件级选择器里重复定义同一变量,比如
.card { --bg: #222; },媒体查询进不去,无法覆盖 -
var(--bg, #fff)的 fallback 值是静态的,不会随媒体查询动态更新,别指望它“智能兜底” - 调试时删掉暗色
:root块,看哪些区域变白——那就是漏定义变量的地方
用户手动切换和系统偏好冲突怎么办
用户点了一次“切暗色”,下次刷新又回系统设置,这是最常被忽略的优先级问题:
- 初始化时顺序必须是:先读
localStorage.getItem('theme')→ 没值再 fallback 到window.matchMedia(...).matches - 监听系统变化时,只在用户没手动选过(即
localStorage为空)才执行切换,否则会覆盖用户意图 - 按钮点击后,除了改
data-theme,必须同步写入localStorage.setItem('theme', next),否则刷新即丢失 - 注意
data-theme="auto"是常见设计,但实现上它只是个标记,实际逻辑仍要靠matchMedia判断
真正容易出问题的不是“怎么写”,而是“什么时候读、什么时候写、什么时候不响应”——这三处逻辑一旦松动,就会出现闪烁、回退、首次加载错乱等现象。

















