HTML暗黑模式不能替代系统主题,它仅通过prefers-color-scheme读取系统偏好且不可写入,需结合matchMedia监听change事件、localStorage持久化用户选择并优先尊重手动设置。

HTML暗黑模式完全不会影响操作系统主题——它只是读取系统偏好,不写入、不控制、不触发任何系统级变更。
prefers-color-scheme 只读不写,系统主题切换不会被网页反向修改
浏览器通过 window.matchMedia("(prefers-color-scheme: dark)") 暴露的是用户在 macOS / Windows / iOS 中设置的「偏好」,属于只读信号。无论你在页面里调用多少次 addEventListener("change", ...),都不会让系统从亮色变暗色,也不会弹出系统设置面板。
- 常见误解:加了
@media (prefers-color-scheme: dark)后,以为能“开启”系统暗黑模式 —— 实际上它连权限都没有 - 真实限制:Windows 10/11 的「深色应用模式」和「系统深色模式」是两个开关;Chrome/Edge 只响应后者,前者对
prefers-color-scheme完全无感 - iOS Safari 在「自动切换(日出日落)」开启时,
matchMedia的change事件可能不触发 —— 这不是 bug,是 Safari 的设计选择,需轮询或放弃实时响应
为什么页面变暗了,但地址栏/滚动条还是亮的
因为 meta[name="color-scheme"] 没写,或者写了但没生效。这个标签不是可选配件,而是原生控件(<input>、<textarea>、滚动条、焦点环)适配系统主题的唯一桥梁。
- 必须写在
<head>内,且内容必须是content="light dark"(双值),单写"dark"会被部分浏览器忽略 - 它只在 HTML 解析阶段起作用,JS 动态设置
document.head.querySelector('meta[name="color-scheme"]').setAttribute(...)无效 - Firefox 对
color-scheme的支持仍不完整,比如<select>下拉箭头可能保持浅色,需额外用appearance: none+ 自定义 SVG 替代
用户手动切了暗色,系统又切回来,页面该听谁的
用户手动选择永远优先。只要 localStorage.getItem("theme") 返回 "dark" 或 "light",就直接采用,不查系统、不监听 change、不 fallback。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
- 错误做法:每次加载都先执行
const mql = window.matchMedia(...); if (mql.matches) setTheme("dark")—— 这会覆盖用户明确点过的偏好 - 正确顺序:立即读
localStorage→ 有值?→ 立即document.documentElement.setAttribute("data-theme", value)→ 结束 - 监听
change仅用于兜底:只在localStorage.getItem("theme") === null时才更新data-theme,否则跳过 - 注意 iOS 无痕模式:
localStorage会被禁用,此时必须 fallback 到matchMedia,但不能把无痕模式当成普通场景处理
CSS 变量没生效,但媒体查询写了,问题出在哪
大概率是变量定义顺序错了,或者被硬编码样式压垮了。CSS 自定义属性不是魔法,它依赖作用域和层叠规则。
-
:root必须先定义默认值::root { --bg: #fff; --text: #000; },否则媒体查询里的覆盖毫无意义 - 媒体查询必须写在默认定义之后:
@media (prefers-color-scheme: dark) { :root { --bg: #121212; } },反过来写会导致暗色下--bg未定义 - 任何一处
style="background: #121212"或div { background: #121212 !important }都会让整套变量机制失效 - 框架组件(如 Chart.js、Tiptap)通常不响应
prefers-color-scheme,得靠data-theme值手动触发重绘,不能指望 CSS 自动穿透
最易被忽略的点:首屏渲染时机。JS 初始化晚于 CSS 加载,就会闪白/闪黑;data-theme 必须在 DOMContentLoaded 前设好,meta[color-scheme] 必须在 <head> 最早位置声明。这两步卡住,后面所有逻辑都白搭。


















