Skip to content
返回设计中心

主题切换与无闪烁加载

持久化用户主题选择、避免 FOUC、与系统偏好同步。

设计令牌进阶

为什么

重载时闪白主题切换是坏 UX。内联阻塞 CSS + 水合前脚本在首绘前设主题,用户永不见错主题。

Tokens Studio(原 Figma Tokens)有 50 万以上安装量,W3C 设计令牌格式模块即将成为候选推荐。令牌从单一来源实现暗色模式、多品牌主题和平台一致性。

何时使用

加暗色模式那一刻就实现无闪烁加载。后补意味着每次重载闪到修好 — 第一次就做对。

如何做

1. <head> 内联脚本 — body 渲染前运行,读 localStorage,设 data-theme 2. 每主题 CSS 变量 — :root[data-theme="dark"] { --color-bg: ... } 3. 持久选择 — localStorage "theme" = "light"|"dark"|"system" 4. 系统同步 — matchMedia("(prefers-color-scheme: dark)") 监听器在 "system" 时更新 5. 切换组件 — 无障碍 switch、aria-label、更新 attr + storage 6. SSR — 服务器读 cookie(非 localStorage)设初始 data-theme,登录用户无闪 7. 过渡 — color-scheme: light dark,加 bg/color 上 150ms 过渡

示例

<!-- index.html — <head> 内联脚本,阻塞首绘 --> <head> <script> (function () { var t = localStorage.getItem("theme") || "system"; var dark = t === "dark" || (t === "system" && matchMedia("(prefers-color-scheme: dark)").matches); document.documentElement.dataset.theme = dark ? "dark" : "light"; })(); </script> </head> /* tokens.css — 每主题变量集 */ :root[data-theme="light"] { --color-bg: #ffffff; --color-text: #111827; } :root[data-theme="dark"] { --color-bg: #0f172a; --color-text: #f3f4f6; } body { background: var(--color-bg); color: var(--color-text); transition: background 150ms, color 150ms; } // ThemeToggle.tsx — 无障碍 switch function ThemeToggle() { const [theme, setTheme] = useState(localStorage.getItem("theme") || "system"); const toggle = () => { const next = theme === "dark" ? "light" : "dark"; setTheme(next); localStorage.setItem("theme", next); document.documentElement.dataset.theme = next; }; return <button onClick={toggle} aria-label="切换暗色模式">{theme === "dark" ? "☀" : "☾"}</button>; }

常见问题

  • ⚠重载 FOUC — 水合后应用主题,用户见白闪后变暗
  • ⚠仅 localStorage — SSR 用户首绘错主题,无 cookie 回退
  • ⚠无系统同步 — 用户 OS 暗模式被忽略,每应用须手动切

最佳实践

  • ✓<head> CSS 前内联主题脚本 — 阻塞首绘,零闪
  • ✓默认提供 'system' — 尊重 OS 设置,显式选择者覆盖之
  • ✓SSR 用 cookie — 服务器读并在 HTML 设 data-theme,登录用户无闪

常见问题解答