2026 年 7 月 30 日约 2 分钟
深色模式不该只是换个背景色
目录
很多深色模式做出来像「把灯关掉」,而好的深色模式应该像「换了个房间」。
不要直接反色
纯黑 #000 配纯白 #fff 的对比度是 21:1,远超阅读需要,长时间看会刺眼,而且在 OLED 屏上会有明显的文字拖影。
我的做法是:背景不用纯黑,文字不用纯白。
:root {
--bg: #ffffff;
--fg: #18181b;
--muted: #71717a;
}
.dark {
--bg: #0b0b0f;
--fg: #e4e4e7;
--muted: #a1a1aa; /* 注意:深色下 muted 要更亮 */
}关键点在 --muted。深色背景上,次要文字需要提高亮度才能保持同样的可读性,直接复用亮色主题的灰度会让正文看不清。
层次靠亮度,不靠阴影
亮色模式里我们用阴影表达「浮起来」。到了深色模式,阴影几乎看不见,应该用表面亮度分层:
- 页面底色:最暗
- 卡片:比底色亮一点点
- 悬浮层/弹窗:再亮一点点
每级大概差 3%~5% 的亮度就够,多了会显得脏。
解决首屏闪白
如果主题存在 localStorage 里,React 水合之前页面已经渲染完了,于是用户会看到一闪而过的亮色。
解法是在 <head> 里塞一段同步执行的内联脚本,在 CSS 生效前就把 class 打到 <html> 上:
try {
const t = localStorage.getItem('theme') ?? 'system'
const dark = t === 'dark' || (t === 'system' &&
matchMedia('(prefers-color-scheme: dark)').matches)
document.documentElement.classList.toggle('dark', dark)
} catch {}再给 <html> 加 suppressHydrationWarning,避免 React 因为服务端/客户端 HTML 不一致报警告。
图片和插画
别忘了图片。纯白底的图片在深色模式下会变成一块刺眼的亮斑。一个便宜的处理方式:
.dark img {
filter: brightness(0.9) contrast(1.05);
}更好的做法是准备两套资源,用 <picture> 配合 prefers-color-scheme 切换。
最后
深色模式的验收标准很简单:在晚上关了灯,用它读十分钟文章,眼睛不累。达不到就继续调。
评论
评论加载中……