0Pricing
React Academy · 课时

持久化主题并防止闪烁

将主题偏好保存到 localStorage,并注入阻塞脚本,在 React 加载前设置主题

持久化主题并防止闪烁 是 CoddyKit 上的免费 React Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。

错误主题闪现问题

页面加载时,React 必须先下载、解析并执行 JavaScript,才能读取 localStorage 并应用正确的主题。在这段间隔期间,浏览器会使用默认样式进行渲染。如果用户偏好深色模式,而您的默认主题是浅色,用户就会先看到短暂的白色闪现,之后主题才会被纠正。

阻塞脚本解决方案

解决方法是在 document head 中放置一个内联脚本,使其在其他代码之前同步运行。该脚本会立即读取 localStorage,并在 document.documentElement 上设置 data-theme。由于这是阻塞脚本,浏览器会在绘制任何内容之前应用该属性。

为何必须阻塞

异步或延迟脚本会在 HTML 解析完成后运行,甚至可能在首次绘制之后才运行。这会完全违背阻止闪现的目的。阻塞内联脚本不能包含 async 或 defer 属性,也不能从外部文件加载。脚本必须足够小,以尽量降低性能开销。

内联脚本内容

阻塞脚本应尽量精简:读取 localStorage.getItem('theme'),将 window.matchMedia('(prefers-color-scheme: dark)').matches 作为备用方案,然后调用 document.documentElement.setAttribute('data-theme', theme)。请将其放在异常捕获结构中,以防在隐私浏览模式下 localStorage 不可用。

Next.js 实现

在 Next.js 中,请使用来自 next/script 的 Script 组件,并在 _document.js 中设置 strategy="beforeInteractive"。beforeInteractive 策略会在任何页面 JavaScript 运行之前,将脚本注入页面 HTML,从而在 Next.js 构建流程中实现相同的阻塞行为。

Vite 和 CRA 实现

在 Vite 或 Create React App 项目中,请直接编辑 index.html,并将内联脚本标签放在 head 中其他脚本之前。由于 index.html 是浏览器的入口点,脚本会在 React 启动之前运行。请保持脚本简洁,使其不超过 100 字节。

通过 Cookie 或请求头实现 SSR

在服务端渲染的应用中,服务器可以从随请求发送的 Cookie 中读取主题。然后,服务器会在将 HTML 发送到浏览器之前,在渲染出的 HTML 中设置 data-theme。这样可以完全避免客户端闪现,因为正确的主题已经存在于 HTML 的第一个字节中。

完整的无闪现流程

完整流程如下:浏览器下载 HTML,解析器遇到阻塞内联脚本,脚本读取 localStorage 并设置 data-theme,解析器继续执行,页面以正确的主题完成绘制,React 完成水合,并从 localStorage 获取相同的主题。用户从一开始看到的就是统一的主题。

测试闪现是否得到阻止

要验证修复是否有效,请打开 Chrome DevTools,进入网络选项卡,并将网络限速为慢速 3G。重新加载页面。如果您在加载期间看到主题发生变化,说明闪现尚未修复。加入阻塞脚本后,即使在网速较慢的连接下,首次绘制也应显示正确的主题。

水合不匹配风险

如果 React 的初始状态默认为浅色,而阻塞脚本在水合前设置了深色,React 可能会针对水合不匹配发出警告。为避免这种情况,请在初始渲染时也读取 localStorage 来初始化 React 主题状态,确保 React 渲染出的 HTML 与阻塞脚本设置的 DOM 状态一致。

Storybook 和测试环境中的闪现

Storybook 和测试环境不会加载您的 index.html,因此阻塞脚本不会运行。请提供一个装饰器或测试设置,在这些环境中应用默认的 data-theme 属性。这样可以避免在独立开发组件时出现令人困惑的视觉不一致。

防止主题闪现的技术

要防止错误主题闪现,必须在文档头部使用哪种脚本?

课程回顾:持久化主题并防止闪现

要防止错误主题闪现,请在文档头部注入一个小型内联阻塞脚本,在任何绘制发生前读取 localStorage 并设置 data-theme。在 Next.js 中使用 strategy="beforeInteractive",在 Vite/CRA 中直接将其添加到 index.html。SSR 应用可以读取 Cookie,在服务端设置主题。

常见问题解答

「持久化主题并防止闪烁」课时是免费的吗?

是的 — 「持久化主题并防止闪烁」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。

「持久化主题并防止闪烁」这节课中我会学到什么?

将主题偏好保存到 localStorage,并注入阻塞脚本,在 React 加载前设置主题 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 React Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「持久化主题并防止闪烁」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 React Academy 课中编写并运行代码吗?

能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 检测系统配色方案
  2. 用于主题切换的 CSS 变量
  3. 使用 React Context 管理主题状态
  4. 持久化主题并防止闪烁
← 返回 React Academy