在 Next.js 中构建无闪烁的深色模式
深色模式看起来很简单。直到你看到了那次“闪烁”。
当用户加载你的页面时,服务器会发送默认主题。在深色主题生效之前,用户会看到一瞬间的白屏。这是一种糟糕的用户体验。
问题在于服务器无法读取 localStorage。只有在浏览器运行你的 JavaScript 之后,服务器才能知道主题。
以下是修复方法。
解决方案:内联脚本 (The Inline Script)
你必须在 React 启动之前应用主题。在你的 <head> 标签中放入一段小的脚本。这段脚本会读取用户偏好并立即添加 dark 类。
请遵循以下步骤:
- 在你的
RootLayout<head>中添加一个脚本来检查localStorage。 - 在你的
<html>标签上使用suppressHydrationWarning。这可以防止 React 报错主题不匹配。 - 使用
ThemeProvider来管理状态并与localStorage同步。 - 使用 Tailwind 的 CSS 变量来实现平滑的颜色过渡。
为什么有效: 脚本在页面渲染之前运行。它防止了视觉上的跳变。
处理图片
图片通常需要针对亮色和深色模式提供不同的版本。你有两个选择:
- CSS 方法:根据
.dark类使用display: none和display: block来切换图片。这是最快的方法。 - 客户端方法:使用一个检查主题并选择正确图片源的组件。
服务端内容的专业技巧
如果你需要服务器通过图表或重型内容感知主题,请使用 cookies 而不是 localStorage。
- 将主题存储在 cookie 中。
- 使用 Next.js
middleware来读取该 cookie。 - 通过
headers将主题传递给你的 layout。
这允许服务器从一开始就发送正确的 HTML。
实现无闪烁系统的总结:
• 在 <head> 中使用内联脚本
• 使用 suppressHydrationWarning
• 使用 Context Provider 管理状态
• 监听系统偏好变化
这种方法适用于生产级应用。它能确保即时切换且完全没有闪烁。