prefers-color-scheme 通过 @media (prefers-color-scheme: dark) 媒体查询原生响应系统深色偏好,需写在 CSS 中、不可嵌套、配合 :root 变量重定义实现颜色切换,注意硬编码颜色、SVG、表单控件及第三方库覆盖问题。

怎么用 prefers-color-scheme 触发深色模式颜色切换
浏览器原生支持,不需要 JS 监听或手动切换类名,@media (prefers-color-scheme: dark) 就是唯一入口点。它只响应系统级深色偏好,不是页面开关——这点常被误当成“主题切换器”来用,结果用户点了按钮没反应。
- 必须写在 CSS 文件里(或
<style>块中),内联 style 不生效 - 不能嵌套在其他媒体查询里(比如不能写成
@media (width > 768px) { @media (prefers-color-scheme: dark) { ... } }) - 优先级和普通规则一致:后定义的会覆盖先定义的,所以通常把深色规则放后面
CSS 变量怎么配合 prefers-color-scheme 动态赋值
变量本身不会“自动变”,得靠媒体查询重新 :root 赋值。很多人直接在 :root 里写两套变量,但漏掉关键一点:深色规则必须包裹在 @media (prefers-color-scheme: dark) 里,否则所有设备都用最后一份值。
:root {
--text-primary: #1a1a1a;
--bg-base: #fff;
}
@media (prefers-color-scheme: dark) {
:root {
--text-primary: #e0e0e0;
--bg-base: #121212;
}
}
- 变量名保持一致,只改值;别在深色块里新加变量,否则浅色下读不到
- 如果用构建工具(如 PostCSS),注意插件是否提前展开了变量——可能让媒体查询失效
- 不要试图在 JS 里读取
getComputedStyle(document.documentElement).getPropertyValue('--text-primary')来判断当前模式,它返回的是静态声明值,不反映媒体查询实际生效结果
为什么有些颜色在深色模式下看起来“灰蒙蒙”或对比度不够
不是媒体查询没生效,而是颜色选得太保守。系统深色模式 ≠ 黑底白字,很多 OS(如 macOS、Windows)用的是深灰(#121212、#1e1e1e),纯黑(#000)反而刺眼;文字也不能简单翻成 #fff,尤其小字号时易发虚。
- 文本色建议用
#e0e0e0~#f0f0f0,避免纯白;背景用#121212~#1e1e1e,避免纯黑 - 强调色(如链接、按钮)要检查 WCAG 对比度,深色下
#2196f3可能不够显,换成#42a5f5更稳 - border、分割线别用
#333,它在深灰背景上几乎看不见,改用#303030或带一点透明度的rgba(255,255,255,0.08)
哪些地方容易忽略导致深色模式“看起来像开了但没完全开”
最常出问题的不是主色调,而是那些没被变量接管的硬编码颜色、图片、SVG 填充、表单控件默认样式。
立即学习“前端免费学习笔记(深入)”;
-
<input type="range">的轨道色、滑块色各浏览器默认不同,深色下可能全黑看不见,得显式重写accent-color或伪元素 - SVG 内联 fill="#333" 不会随 CSS 变量变,要么改成
fill: var(--icon-fill),要么用currentColor - 图片没有
picture+media="(prefers-color-scheme: dark)"切换,深色下图标可能反光或看不清 - 第三方组件库(如 Ant Design、MUI)若没启用深色模式支持,它们的 CSS 会盖掉你的变量,得查文档配
theme或加!important强制










