prefers-color-scheme在Chrome 76+、Firefox 67+、Safari 12.1+、Edge 79+原生支持,但Safari 12.1–13.0存在切换后不重算的bug,需JS兜底;必须同时声明light和dark媒体查询,并以浅色为默认样式防闪屏。

prefers-color-scheme 在哪些浏览器里能用
Chrome 76+、Firefox 67+、Safari 12.1+ 和 Edge 79+ 原生支持 prefers-color-scheme,但 Safari 12.1–13.0 有 bug:切换系统主题后不会触发媒体查询重计算,必须刷新页面;iOS Safari 13.0+ 才真正可靠。旧版 Edge(EdgeHTML)完全不支持,IE 不支持。
所以不能只靠它做唯一判断,尤其要兼顾 Safari 旧版本和用户手动切换场景。
怎么写基础媒体查询才不漏样式
必须同时覆盖 light 和 dark,且默认样式(无媒体查询)建议设为浅色,避免深色模式下白底黑字闪屏。不要只写 @media (prefers-color-scheme: dark) 就完事——漏掉 light 会导致某些浏览器回退到不可控的默认值。
@media (prefers-color-scheme: light) { body { background: #fff; color: #333; } }@media (prefers-color-scheme: dark) { body { background: #1e1e1e; color: #eee; } }- 所有颜色变量建议统一用 CSS 自定义属性(
--bg-color、--text-color),方便后续 JS 控制或 fallback
怎么应对 Safari 12.1–13.0 的重绘失效
Safari 这个版本在系统切换深色/浅色后,prefers-color-scheme 媒体查询不会重新匹配,导致页面样式卡住。最简单有效的补救是监听 storage 事件 + 手动触发重绘:
立即学习“前端免费学习笔记(深入)”;
if (window.matchMedia && window.matchMedia('(prefers-color-scheme)').media !== 'not all') {
// Safari 12.1+ 检测到支持但可能不响应变化
const media = window.matchMedia('(prefers-color-scheme: dark)');
const updateTheme = () => document.documentElement.setAttribute('data-theme', media.matches ? 'dark' : 'light');
updateTheme();
media.addEventListener('change', updateTheme);
}然后在 CSS 中加一层兜底:
[data-theme="dark"] { /* 深色样式 */ }
[data-theme="light"] { /* 浅色样式 */ }这样即使媒体查询没更新,JS 也能强制同步。
要不要加 JS 主动控制开关
纯靠系统偏好不够——用户可能想手动覆盖。这时别用 localStorage 存布尔值再塞进 class,容易和媒体查询冲突。推荐三态管理:auto(跟随系统)、light、dark,并优先级:JS 设置 > 系统偏好。
- 读取时:先看
localStorage.theme,若为auto再查matchMedia - 设置时:更新
localStorage并同步document.documentElement.dataset.theme - CSS 中仍保留媒体查询,但只作为
auto模式下的 fallback,避免样式打架
深色模式兼容真正的难点不在语法,而在「系统偏好」和「用户意图」的优先级协调——一旦 JS 主动介入,就必须全程接管,不能让媒体查询和 JS 各自为政。


















