prefers-color-scheme 是浏览器原生支持的 css 媒体查询,用于检测系统暗黑/亮色主题,需配合 :root 变量和 media 查询实现双主题,注意 safari 的 color-scheme meta 和 file:// 协议限制。

如何用 prefers-color-scheme 检测系统主题
浏览器原生支持通过媒体查询判断用户系统是否启用暗黑模式,关键就是 prefers-color-scheme。它不是 JavaScript API,不触发重排,也不依赖 JS 加载——只要 CSS 被解析,样式就立即生效。
注意:该特性在 Chrome 76+、Firefox 67+、Safari 12.1+ 和 Edge 79+ 中可用;旧版本(如 iOS 12 Safari)不支持,@media (prefers-color-scheme: dark) 会被直接忽略,不会报错,但也不会生效。
- 只接受三个值:
light、dark、no-preference(极少触发,通常可忽略) - 不能用 JS 动态监听变化(除非用
window.matchMedia主动监听) - 值由操作系统或浏览器设置决定,网页无法覆盖或模拟(开发调试时可在 Chrome DevTools → Rendering 面板中强制切换)
怎么写一套基础的暗黑/亮色双主题 CSS
最稳妥的方式是「默认写亮色样式,再用 @media (prefers-color-scheme: dark) 覆盖」。这样即使媒体查询不被支持,页面仍能显示合理的基础样式。
不要把所有颜色都写死在 dark 块里——优先复用 CSS 自定义属性(:root 变量),便于维护和后续扩展。
:root {
--bg: #fff;
--text: #333;
--border: #e0e0e0;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #e0e0e0;
--border: #333;
}
}
body {
background-color: var(--bg);
color: var(--text);
border: 1px solid var(--border);
}
- 避免在
@media块内重复声明非颜色相关样式(比如字体大小、间距),只覆盖真正需要变的部分 - 慎用
!important—— 它会破坏变量继承链,让后续主题扩展(比如高对比度模式)难以介入 - 图片、SVG 图标中的颜色若需随主题切换,得用
currentcolor或内联fill+ CSS 变量控制
遇到 prefers-color-scheme 不生效的常见原因
写完代码却没反应?大概率不是语法错,而是这几个隐性条件没满足:
- 页面未声明
<meta name="color-scheme" content="light dark">—— 这个 meta 标签虽非必需,但在 Safari(尤其 iOS)中缺失时,prefers-color-scheme: dark可能被忽略或延迟应用 - 本地开发用
file://协议打开 HTML —— Safari 和部分旧版 Chrome 在 file 协议下会禁用prefers-color-scheme查询 - CSS 文件被缓存,且之前加载过一次未带 media 查询的版本 —— 强制刷新(
Cmd+Shift+R)或禁用缓存再试 - 元素背景用了
background: #fff这类硬编码值,没走var(--bg),导致覆盖失效
要不要用 JavaScript 补充监听主题切换
如果业务需要在主题切换时触发逻辑(比如保存用户偏好、重绘 Canvas、调整第三方图表库),就得用 window.matchMedia。
但注意:这不是为了“实现暗黑模式”,而是为了“响应变化”。CSS 本身已足够完成样式切换。
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
function handleSchemeChange(e) {
document.documentElement.dataset.scheme = e.matches ? 'dark' : 'light';
}
darkModeQuery.addEventListener('change', handleSchemeChange);
handleSchemeChange(darkModeQuery); // 初始化
- 别在
DOMContentLoaded之前读取matchMedia结果,某些浏览器可能返回空对象 - 服务端渲染(SSR)场景下,
prefers-color-scheme无法在首屏直出时生效,必须靠客户端 JS 注入或配合script type="module"延迟执行 - 用户手动覆盖系统设置(比如网页内设“强制暗黑”开关)时,
matchMedia不会触发,需自行管理状态
file:// 协议的限制和缺少 <meta name="color-scheme"> 导致的 iOS 兼容断层。调色本身很简单,卡住的往往是最外层的环境条件。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











