← 全部文章

教程

为任何网站启用深色模式 —— 4 种 CSS 方案

你的操作系统多年前就有了深色模式。你的浏览器也支持它。大多数应用都遵守它。然后你打开一份文档、一个博客或一个 2014 年的内网 —— 晚上 11 点迎面被一片 100% 纯白背景糊一脸。四种方法,一劳永逸地解决它。

这个问题为什么存在

CSS 标准 prefers-color-scheme 自 2019 年起进入 Chrome、2018 年起进入 Safari。你的操作系统知道你的偏好,浏览器把它传递下去,网站本应遵守。本应 —— 而实际上约 40% 的网站对它视而不见。原因:祖传代码、没有预算做第二套主题、市场部想要「品牌一致性」、作者还没想到这茬。

如果作者不替你做 —— 那就自己来。四种方法,按优雅程度递增排列。

方法 1 —— 通用滤镜(对一切都管用)

一段代码,适配任何网站,无需分析具体的 CSS:

html {
  filter: invert(0.92) hue-rotate(180deg);
  background: #1a1a1a;
}

/* 把图片、视频和 iframe 再次反色,让它们看起来
   自然 —— 否则你朋友的自拍看上去会像加了
   绿脸滤镜。 */
img, video, picture, iframe, svg,
[style*="background-image"] {
  filter: invert(1) hue-rotate(180deg);
}

小技巧:用 invert(0.92) 而不是完全的 invert(1),会得到比纯白→纯黑硬切更柔和的黑 —— 对眼睛更友好。hue-rotate(180deg) 会校正颜色,让橙色仍然是橙色(而不会变成蓝色)。

优点:处处可用,零分析。
缺点:阴影、渐变、微妙的灰度会显得怪异。某些 fixed 元素(粘性页头)在滚动时可能错位。

方法 2 —— 强制 prefers-color-scheme: dark

有些网站本来就有深色模式,但只对系统偏好作出反应。如果你把操作系统保持在浅色(因为你在用 Figma 做设计),却想让 GitHub 文档变深色呢?覆盖 matchMedia:

// 用 JS 强制 prefers-color-scheme: dark
const dark = window.matchMedia('(prefers-color-scheme: dark)');
Object.defineProperty(dark, 'matches', {
  get: () => true,
  configurable: true,
});

// 通知监听器(通过 addEventListener 挂钩的网站)
dark.dispatchEvent(new Event('change'));

它在任何使用 window.matchMedia('(prefers-color-scheme: dark)') 进行检测的网站上都有效 —— 所有现代 React/Vue 应用。它不适用于那些只在加载时检测一次的网站(你得重新加载),也不适用于没有 JS 检测的静态 CSS。

方法 3 —— 覆盖 CSS 自定义属性

基于 CSS 变量构建的网站(约 60% 的现代 Web 应用)通常有像 --bg-primary--text-primary 这样的主题令牌。打开 DevTools,找到这些名字,覆盖它们:

/* 示例:Stripe Dashboard,那里一切都基于变量 */
:root {
  --color-canvas-default: #0d1117 !important;
  --color-canvas-subtle: #161b22 !important;
  --color-fg-default: #c9d1d9 !important;
  --color-fg-muted: #8b949e !important;
  --color-border-default: #30363d !important;
}

优点:精确,不会破坏图片或阴影。
缺点:要在 DevTools 里挖 5 分钟才能找到变量名。网站必须使用 CSS 变量(在控制台用 document.documentElement.style 验证)。

方法 4 —— 为单个站点定制专属深色主题

对于那些你每天泡上好几个小时的网站 —— 花 30 分钟做一套量身定制的主题是值得的。有选择地覆盖:

/* 你那个普普通通的公司内网 */
body, .page-content, .sidebar, .top-bar {
  background: #1a1a1a !important;
  color: #e0e0e0 !important;
}

.card, .panel, .modal {
  background: #242424 !important;
  border-color: #333 !important;
}

a, a:visited { color: #58a6ff !important; }
a:hover { color: #79c0ff !important; }

input, textarea, select {
  background: #1a1a1a !important;
  color: #e0e0e0 !important;
  border-color: #444 !important;
}

/* 表格 —— 对可读性最为关键 */
table th { background: #2d2d2d !important; color: #fff !important; }
table tr:nth-child(odd) { background: #1f1f1f !important; }
table tr:nth-child(even) { background: #1a1a1a !important; }

从主要容器(body、page)开始,往下深入到组件(卡片、模态框),最后收尾在表单元素和表格上。没有 !important 通常赢不了 —— 网站自己的样式具有更高的优先级。

常见的坑

如何在 JustZix 中接入

  1. 安装 JustZix(2 分钟)。
  2. 创建一个叫「深色模式」的文件夹。
  3. 规则「处处深色模式」:URL 模式 *,CSS = 方法 1。默认设为未启用 —— 需要时再打开。
  4. 为常用站点设规则:模式 https://myapp.com/*,CSS = 方法 3 或 4(带具体令牌 / 选择器)。始终启用。
  5. 用悬浮按钮一键切换整个文件夹 —— 一步切换明暗。

接下来做什么

同样的层次结构(通用 → 针对单站点的精确处理)也适用于其他规则类别 —— 参见示例应用场景。深色模式只是其中最显而易见的案例。

免费安装 JustZix,终于掌控那些你每天盯着 8 小时的网站长什么样。

为这篇文章评分

暂无评分 — 成为第一个。

自己动手试试

安装 JustZix,粘贴本文中的任意代码片段。两分钟,从零到一条在你所有设备上生效的规则。

获取 JustZix

功能 · 工作原理 · 示例 · 应用场景