prefers-color-scheme 是 CSS 媒体查询,用于响应系统级暗黑/亮色偏好,仅支持 dark、light、no-preference 三种值,不触发重排,需配合 color-scheme meta 标签和 CSS 属性以正确渲染原生控件。

如何用 prefers-color-scheme 检测系统主题
浏览器原生支持系统暗黑/亮色偏好,关键就靠 CSS 媒体查询 @media (prefers-color-scheme: dark)。它不是 JavaScript API,不触发重排,也不依赖用户手动切换开关——只要系统设置变了,CSS 就自动生效。
注意:这个媒体查询只响应系统级设置(macOS 的“深色模式”、Windows 10+ 的“颜色 > 选择模式”、iOS/iPadOS 的“显示与亮度 > 外观”),不响应浏览器内置的“暗黑主题”开关(如 Chrome 的 chrome://settings/appearance)。
-
prefers-color-scheme在 Safari 12.1+、Chrome 76+、Firefox 67+、Edge 79+ 完全可用;IE 不支持,无需兼容 - 值只有
dark、light、no-preference三种,其中no-preference极少见(通常出现在无障碍辅助场景) - 不能用 JS 直接读取当前值(
window.matchMedia可监听但不能获取“当前系统值”,需用matchMedia('(prefers-color-scheme: dark)').matches判断)
color-scheme meta 标签和 CSS 属性的作用区别
<meta name="color-scheme" content="light dark"> 是告诉浏览器:“我的页面支持亮色和暗色”,仅影响表单控件(<input>、<select>)、滚动条、焦点环等原生 UI 元素的默认渲染风格,**不会改变你写的 CSS 颜色**。
而 color-scheme CSS 属性(如 body { color-scheme: light dark; })作用范围更细,可设在任意元素上,用于声明该元素及其子元素内原生控件应遵循的配色策略。两者配合才能让表单在暗黑模式下真正“看起来像系统风格”。
立即学习“前端免费学习笔记(深入)”;
- 没加
<meta>标签时,Chrome/Firefox 会默认按light渲染表单,即使 CSS 里写了background: #121212,输入框边框仍可能是浅灰 -
color-scheme: dark不会强制把文字变白——它只影响浏览器对accent-color、caret-color等的解析逻辑,以及是否启用系统暗色滚动条 - 移动端 Safari 对
color-schememeta 支持较晚(iOS 13.4+),旧版需 fallback 到 JS 检测 + class 切换
为什么 JS 主动切换暗黑模式后,prefers-color-scheme 不再响应系统变化
一旦你在 JS 中通过 document.documentElement.classList.add('dark') 手动设了主题,并用 CSS 规则覆盖所有颜色(比如 .dark h1 { color: white; }),那 @media (prefers-color-scheme: dark) 就彻底失效了——因为它的规则被更高优先级的选择器压住了,且不再参与匹配逻辑。
这不是 bug,是层叠规则的自然结果。要保留系统协同能力,必须让 CSS 媒体查询始终是“最终决定者”,而不是中间一环。
- 推荐做法:完全用
@media控制颜色,不写.dark类;用户手动切换时,改用localStorage记录偏好,然后动态插入或移除<style>块,或切换data-theme属性并用属性选择器(如html[data-theme='dark'] h1) - 如果必须用 class,确保媒体查询规则的优先级高于 class 规则(例如用
html.dark h1vs@media (prefers-color-scheme: dark) h1,后者优先级更低) - 别在 JS 里调用
matchMedia后直接classList.toggle——这会让页面在系统切换时“卡住”,除非你监听mediaQueryList.addEventListener('change', ...)
暗黑模式下字体抗锯齿和 contrast() 滤镜的坑
暗色背景上文字发虚、边缘模糊?不是字体问题,大概率是 macOS 启用了“使用图形增强”(即 subpixel antialiasing),而深色背景下 subpixel 渲染会出错。CSS font-smooth 已废弃,正确解法是:
- 加
* { -webkit-font-smoothing: antialiased; }(Safari/macOS) - 加
* { text-rendering: optimizeLegibility; }(提升连字和字距) - 避免对文字使用
filter: contrast(1.2)—— 它会干扰浏览器的 gamma 校正,在暗色模式下让灰字显得过亮或发紫,尤其在 OLED 屏上明显 - 慎用
backdrop-filter: blur()叠在暗色模态框上:Safari 会意外提亮底层内容,导致对比度崩坏;可改用半透rgba(0, 0, 0, 0.7)+box-shadow模拟
系统主题协同真正的难点不在检测,而在放弃“我来控制一切”的执念——让 CSS 媒体查询做主,把 color-scheme 当作表单的授权许可,而不是颜色方案的总开关。很多视觉异常,其实只是某一层规则悄悄覆盖了系统信号。



















