跳到主内容
← 全部文章

2026 年 7 月 30 日2 分钟

深色模式不该只是换个背景色

#CSS#设计

目录

很多深色模式做出来像「把灯关掉」,而好的深色模式应该像「换了个房间」。

不要直接反色

纯黑 #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 切换。

最后

深色模式的验收标准很简单:在晚上关了灯,用它读十分钟文章,眼睛不累。达不到就继续调。

评论

0 / 500

无需登录,昵称和评论会公开显示。

评论加载中……