在 Next.js 中构建无闪烁的深色模式

深色模式看起来很简单。直到你看到了那次“闪烁”。

当用户加载你的页面时,服务器会发送默认主题。在深色主题生效之前,用户会看到一瞬间的白屏。这是一种糟糕的用户体验。

问题在于服务器无法读取 localStorage。只有在浏览器运行你的 JavaScript 之后,服务器才能知道主题。

以下是修复方法。

解决方案:内联脚本 (The Inline Script)

你必须在 React 启动之前应用主题。在你的 <head> 标签中放入一段小的脚本。这段脚本会读取用户偏好并立即添加 dark 类。

请遵循以下步骤:

  • 在你的 RootLayout <head> 中添加一个脚本来检查 localStorage
  • 在你的 <html> 标签上使用 suppressHydrationWarning。这可以防止 React 报错主题不匹配。
  • 使用 ThemeProvider 来管理状态并与 localStorage 同步。
  • 使用 Tailwind 的 CSS 变量来实现平滑的颜色过渡。

为什么有效: 脚本在页面渲染之前运行。它防止了视觉上的跳变。

处理图片

图片通常需要针对亮色和深色模式提供不同的版本。你有两个选择:

  • CSS 方法:根据 .dark 类使用 display: nonedisplay: block 来切换图片。这是最快的方法。
  • 客户端方法:使用一个检查主题并选择正确图片源的组件。

服务端内容的专业技巧

如果你需要服务器通过图表或重型内容感知主题,请使用 cookies 而不是 localStorage

  • 将主题存储在 cookie 中。
  • 使用 Next.js middleware 来读取该 cookie。
  • 通过 headers 将主题传递给你的 layout。

这允许服务器从一开始就发送正确的 HTML。

实现无闪烁系统的总结:

• 在 <head> 中使用内联脚本 • 使用 suppressHydrationWarning • 使用 Context Provider 管理状态 • 监听系统偏好变化

这种方法适用于生产级应用。它能确保即时切换且完全没有闪烁。

来源:https://dev.to/aon_infotech_3a1b6ff525fc/building-a-dark-mode-system-in-nextjs-app-router-without-layout-flash-5gf9