用prefers-color-scheme检测深色模式需依赖css媒体查询@media (prefers-color-scheme: dark),浏览器原生支持、不触发重排、响应系统级设置,无需js;须配合默认浅色样式兜底,并通过css变量统一管理主题色。

如何用 prefers-color-scheme 检测深色模式
浏览器原生支持深色模式检测,靠的就是 prefers-color-scheme 媒体查询,它不是 JavaScript API,不触发重排,也不依赖用户代理字符串——只响应系统级设置。iOS 13+、macOS 10.14+、Android 10+、Chrome 76+、Firefox 67+、Safari 12.1+ 都已支持。
常见错误是把它当 JS 条件用,比如写 if (window.matchMedia('(prefers-color-scheme: dark)').matches) 再手动加 class——完全没必要。纯 CSS 就能覆盖绝大多数场景。
- 只在根元素或组件级写媒体查询,避免嵌套过深导致优先级混乱
- 不要和
@media (max-width: ...)混写成一条规则(如@media (max-width: 768px) and (prefers-color-scheme: dark)),移动端宽度判断应独立处理,深色模式是全局偏好,和尺寸无关 - Windows 10/11 的“深色应用模式”不触发该查询,只有“深色系统模式”才生效;iOS 中需在「设置 → 显示与亮度 → 深色」开启,且 Safari 必须重启一次才能同步状态
深色模式下字体和背景色怎么设才不刺眼
直接把 background-color: #000 和 color: #fff 往里一塞,大概率翻车。纯黑背景会加剧 OLED 屏幕的视觉疲劳,文字对比度过高反而降低可读性。
推荐用偏灰的深色系,并保留语义化颜色变量,方便后续扩展:
html {
--bg-base: #ffffff;
--text-primary: #1a1a1a;
--border-light: #e0e0e0;
}
@media (prefers-color-scheme: dark) {
html {
--bg-base: #121212;
--text-primary: #e0e0e0;
--border-light: #333;
}
}
body {
background-color: var(--bg-base);
color: var(--text-primary);
border-color: var(--border-light);
}
- OLED 手机建议用
#121212而非#000000,功耗更低、观感更柔和 - 文字色别用纯白,
#e0e0e0或#f5f5f5更合适;正文行高建议提高到 1.6–1.8,弥补深色背景下字符边缘轻微发虚的问题 - 慎用
box-shadow: 0 0 10px rgba(0,0,0,0.5)类阴影——深色模式下几乎不可见,应改用rgba(255,255,255,0.1)等浅色半透阴影
图片和 SVG 在深色模式下显示异常怎么办
SVG 图标默认是矢量路径,没有背景,但若用了 fill="#333" 或内联 style,就不会随主题切换;位图(PNG/JPG)更麻烦——白色背景的图标在深色下直接“消失”。
- SVG 推荐用
fill="currentColor",让它继承父元素的color,再配合 CSS 变量统一控制 - 关键图标(如 logo)准备两套:一套浅色主色 + 白底,一套深色主色 + 透明底,用
picture+source media切换:<picture><source srcset="logo-dark.svg" media="(prefers-color-scheme: dark)"> @@##@@ </source></picture>
- 避免对
<img src="logo-light.svg" alt="logo">元素本身写background-color,它不生效;需要底色请包一层<div> 并设背景 <h3>为什么 iOS Safari 深色模式下 input placeholder 不变色</h3> <p>iOS Safari 对 <code>::placeholder伪元素在深色模式下的样式继承有 Bug:即使父元素 color 已更新,placeholder 仍固执地显示为浅灰色(#999)。这不是你漏写了媒体查询,是渲染层限制。- 必须显式重写
::placeholder的 color,在深色媒体查询里单独定义:@media (prefers-color-scheme: dark) { input::placeholder, textarea::placeholder { color: #666; } } - 不要依赖
inherit或currentcolor,iOS Safari 15.4 之前都不支持它们在::placeholder中生效 - 如果用了 CSS-in-JS(如 styled-components),确保媒体查询包裹的是最终生成的 class,而不是 JS 判断后插入的 style 标签——后者无法被 Safari 正确监听系统变化
深色模式适配真正的难点不在“怎么写”,而在“什么时候该让步”:比如用户开了深色系统,但你的图表库强制用亮色坐标轴,这时候硬切主题反而破坏数据可读性。优先保功能,再谈风格。
- 必须显式重写











