问题
Quartz 站点部署后,macOS 暗色模式下页面几乎看不清内容——背景接近白色,文字对比度极差。
排查过程
Round 1:颜色语义搞反了
Quartz 的颜色变量命名和直觉相反:
| 变量 | 实际含义 | 容易误解为 |
|---|---|---|
light | 页面背景色 | 浅色文字 |
dark | 标题文字色 | 深色背景 |
darkgray | 正文文字色 | 深灰背景 |
gray | 侧边栏/次要文字 | — |
secondary | 链接/标签色 | — |
tertiary | 悬停色 | — |
初始配置把 darkMode.light 设成了 #e2e8f0(浅灰色),结果暗色模式的背景是浅灰色。
修复:light: "#0a0e1a"(深蓝黑)。
Round 2:对比度不足
背景修正后,文字颜色对比度仍然不够:
| 变量 | 修改前 | 修改后 | 原因 |
|---|---|---|---|
gray | #64748b | #94a3b8 | 侧边栏文字太暗 |
darkgray | #cbd5e1 | #e2e8f0 | 正文需要更亮 |
dark | #f1f5f9 | #f8fafc | 标题接近纯白 |
secondary | #7c3aed | #a78bfa | 链接对比度 3.8:1 不达标 |
tertiary | #3b82f6 | #60a5fa | 悬停色提亮 |
Round 3:CSS 媒体查询兜底
添加了 @media (prefers-color-scheme: dark) 作为 JS 检测的 CSS 级兜底,防止 prescript.js 加载前的白屏闪烁。
Round 4:浏览器缓存(真正的元凶)
前三轮修复都已部署到服务器,但用户刷新页面后仍然看到白色背景。
排查发现 nginx 配置:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}immutable 标记告诉浏览器:这个文件永远不会变,不需要重新验证。浏览器缓存了旧的 index.css(不含暗色模式修复),30 天内不会请求新版本。
immutable缓存的陷阱
immutable适用于文件名包含 hash 的资源(如app.3a2b1c.css),因为内容变了文件名也变。但 Quartz 生成的index.css文件名不变,用immutable会导致更新无法送达用户。
修复:区分缓存策略
# CSS/JS: 允许缓存但每次验证(ETag/Last-Modified)
location ~* \.(js|css)$ {
add_header Cache-Control "no-cache";
}
# 图片/字体: 长缓存(内容稳定)
location ~* \.(png|jpg|jpeg|gif|ico|svg|woff|woff2|webp)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}no-cache 不是”不缓存”,而是”缓存但每次请求前用 ETag 验证”。如果文件没变,服务器返回 304(无需重新下载);如果变了,返回新文件。兼顾了性能和及时更新。
Quartz 暗色模式工作原理
prescript.js(同步阻塞脚本)
↓
window.matchMedia("(prefers-color-scheme: light)")
↓ 检测系统偏好
localStorage.getItem("theme") ?? 系统偏好
↓ localStorage 优先
document.documentElement.setAttribute("saved-theme", "dark")
↓ 设置 HTML 属性
CSS: :root[saved-theme="dark"] { --light: #0a0e1a; ... }
↓ CSS 变量覆盖
页面渲染为暗色
教训
- 读懂颜色语义:
light不是”浅色文字”,是”背景色”。部署前先查 Quartz 文档 - WCAG 对比度:暗色背景上文字至少 4.5:1(AA 标准),用 WebAIM Contrast Checker 验证
immutable慎用:只用于文件名含 hash 的资源。其他文件用no-cache(每次验证)或短max-age- 修复后看不到效果?先查缓存:
curl -I检查Cache-Control头,比调代码有效得多