prefers-color-scheme 在 ios 12/android 9 及以下不支持,需用 localstorage 或 url 参数 fallback,并通过 class 切换主题、内联 script 初始化、顶层 color-scheme 声明确保兼容性。

prefers-color-scheme 在 iOS 12 / Android 9 及以下版本根本不会返回 true —— 不是你 CSS 写错了,是浏览器压根没实现这个 API。
怎么快速判断 prefers-color-scheme 是否可用
别猜,直接在控制台执行:window.matchMedia('(prefers-color-scheme: dark)').matches。如果始终返回 false,哪怕系统已设为深色,说明当前环境(比如微信内置浏览器、旧版安卓 WebView)不支持该特性。Safari 13+、Chrome 76+、Firefox 96+ 才开始稳定支持;iOS 13+ 和 Android 10+ 是分水岭。
注意:file:// 协议下 Safari 会禁用该查询;DevTools 模拟器能切 ≠ 真机 WebView 支持;部分厂商定制壳默认关闭透传。
必须 fallback 到 localStorage 或 URL 参数
不能只依赖媒体查询做唯一判断,初始化时就得兜底:
- 优先读
localStorage.getItem('themeMode'),比如用户上次手动选了dark - 若为空,再 fallback 到
window.matchMedia('(prefers-color-scheme: dark)').matches - 两者都为空时,可用时间逻辑兜底(如
hour >= 19 || hour ),但别默认亮色——护眼需求可能正等着暗色 - 千万别把
null直接赋给dataset.theme,否则生成data-theme="null",CSS 选择器匹配失败
用 class 切换比 setProperty 更可靠
很多人用 document.documentElement.style.setProperty('--bg', '#121212') 覆盖变量,但伪元素、SVG、原生表单控件、第三方组件往往不响应 CSS 变量,只认 class 或 data- 属性。
更稳的做法:
- 给
html元素加class="dark",所有深色规则写成.dark .btn、.dark input这种形式 - Tailwind 用户确认
tailwind.config.js中darkMode: 'class'已启用 - 切换时同步调用
localStorage.setItem('themeMode', 'dark'),否则刷新就还原 -
.dark { color-scheme: dark; }让浏览器接管滚动条、按钮、输入框等 UA 样式
首屏闪白/闪黑的根本原因是渲染时机错位
闪屏不是动画问题,是 HTML 解析完、CSS 加载前,浏览器按默认主题渲染了第一帧;等 JS 执行完、class 加上,才重绘——这中间的“白帧”在移动端尤其刺眼。
解决方法只有一个:把初始判断逻辑放到 <script></script> 内联脚本中,且必须早于任何外链 CSS 和 DOM 渲染。不要等 DOMContentLoaded,那时已经晚了。
复杂点在于 SSR 场景:服务端无法读客户端偏好,必须配合 data-color-scheme 属性 + 关键 CSS 内联,否则 hydration 前后样式撕裂不可避免。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











