用 @media (prefers-color-scheme: dark) 可原生响应系统深色模式,无需 JS;需配合 CSS 自定义属性统一管理颜色,并添加 color-scheme: light dark 声明以适配表单控件。

如何用 prefers-color-scheme 检测系统深色模式
浏览器原生支持,不需要 JS 就能响应系统设置。关键在于媒体查询 @media (prefers-color-scheme: dark) —— 它不是“监听器”,而是一次性匹配,系统切换时会自动重算并应用新样式。
注意:它只在支持该特性的浏览器中生效(Chrome 76+、Firefox 67+、Safari 12.1+、Edge 79+),旧版 Safari 需要加 -webkit- 前缀但实际无效,直接忽略即可。
- 必须写在 CSS 文件或
<style></style>标签里,内联 style 不支持媒体查询 - 不能用 JS 动态插入该媒体查询规则(
insertRule会静默失败) - 匹配逻辑是“当前系统设置”,不是“用户曾经点过深色按钮”——所以不要把它当 UI 主题开关用
怎么写深色/浅色两套样式才不重复又可控
推荐用 CSS 自定义属性(color-scheme 是另一回事,别混)统一管理颜色变量,再用媒体查询覆盖。避免为每个元素写两遍 color/background。
:root {
--bg: #fff;
--text: #333;
--border: #e0e0e0;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #e0e0e0;
--border: #333;
}
}
body {
background: var(--bg);
color: var(--text);
border: 1px solid var(--border);
}
这样改主题只需改 :root 里的变量值,不用动业务样式。如果项目已有大量硬编码颜色,建议先全局搜索 #fff、#000 等高频值,逐步替换成变量。
立即学习“前端免费学习笔记(深入)”;
为什么用了 prefers-color-scheme 但页面没变色
常见原因不是代码写错,而是环境或优先级问题:
- 开发服务器没开 HTTPS:某些浏览器(如 Safari 技术预览版)在 HTTP 下禁用该特性
- CSS 文件被缓存,且你改了媒体查询但没清缓存(尤其 Vite/HMR 有时不触发重载)
- 其他 CSS 规则优先级更高,比如
.card { background: black !important; }直接覆盖了变量值 - 系统设置没真正生效:macOS 要在「系统设置 → 外观」选“自动”,Windows 要在「设置 → 个性化 → 颜色 → 选择默认 Windows 模式」设为“暗色”或“自动”
要不要搭配 color-scheme 声明
要,但作用完全不同:color-scheme 是告诉浏览器“我支持深色模式”,让表单控件(<input>、<select></select>)、滚动条、焦点框等自动适配系统主题;而 prefers-color-scheme 是让你自己写样式。
加一行就行,放在 :root 或 html 上:
:root {
color-scheme: light dark;
}
不加的话,浏览器可能强制把表单控件渲染成浅色,和你的深色背景打架。iOS Safari 尤其明显——没有这行,<input type="range"> 的滑块永远是亮的。
复杂点在于:如果你用 CSS 自定义了所有表单样式(比如重写了 appearance: none),那 color-scheme 就没用了,但你也得自己处理所有控件的深色逻辑。


















