应使用 css 变量配合 prefers-color-scheme 媒体查询实现深色模式,先在 :root 定义浅色默认值,再于 @media (prefers-color-scheme: dark) 中覆盖变量;需支持用户手动覆盖(通过 data-theme 属性控制优先级),并全面适配表单、svg、图片等易忽略元素。

如何用 prefers-color-scheme 检测系统深色偏好
浏览器原生支持系统级深色/浅色设置检测,关键就是 prefers-color-scheme 媒体查询。它不依赖 JS,不触发重排,加载即生效——前提是用户没手动覆盖。
常见错误是只写 @media (prefers-color-scheme: dark) 就完事,但漏掉默认浅色样式兜底,导致深色模式下部分元素没定义而显白底黑字(尤其自定义组件)。
- 必须先定义基础色值(以浅色为默认),再用媒体查询覆盖深色变量
- 不要在
:root里直接写深色值,否则浅色模式会继承错 - Windows/macOS/iOS 的开关路径不同,但该媒体查询在 Chrome 76+/Firefox 67+/Safari 12.1+ 均可用
为什么必须用 CSS 变量(--color-bg)而不是直接写死颜色
硬编码颜色(如 background: #1e1e1e)会导致深色模式切换时需重复写两套规则,维护成本高且易漏。CSS 变量让主题逻辑集中、可继承、可动态更新。
典型陷阱:把变量定义在媒体查询内部,结果其他地方引用时未定义(比如在 :root 外声明)。
- 所有主题变量必须在
:root中初始化(默认浅色值) - 深色覆盖写在
@media (prefers-color-scheme: dark)内部的:root里 - 变量名建议带语义,如
--color-surface比--bg-1更易协作
:root {
--color-bg: #ffffff;
--color-text: #333333;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #121212;
--color-text: #e0e0e0;
}
}
如何让深色模式「可被用户手动覆盖」而不破坏系统检测
纯靠 prefers-color-scheme 不够——用户可能系统设浅色,但偏爱网页深色;或反之。需要加一层手动开关,且优先级高于系统检测。
错误做法:用 JS 切换 class="dark" 后,又保留媒体查询,导致逻辑打架。
- 推荐方案:用一个 data 属性(如
data-theme="dark")作为最高优先级信号 - 媒体查询只作为 fallback,写在手动主题之后(CSS 层叠顺序决定优先级)
- JS 仅负责存取
localStorage和设置data-theme,不操作样式表 - 注意:手动切换后要同步更新
prefers-color-scheme的监听,避免系统切换时覆盖用户选择
哪些样式容易被忽略导致深色模式「看起来怪」
很多人只改了 background 和 color,但图片边框、阴影、表单控件、SVG fill、甚至 hr 颜色都没适配,造成视觉割裂。
特别注意:表单元素(input、textarea、select)在深色模式下默认背景常是浅灰,文字却变暗,对比度崩坏。
- 务必重置
border-color、box-shadow、outline的变量值 -
img建议加filter: brightness(0.85)(深色下轻微降亮)避免刺眼 - SVG 图标若用
fill="currentColor"可自动跟随color,否则需单独设变量 - 检查所有硬编码的
#000/#fff,替换成对应变量
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











