使用 Tailwind CSS 基于类的暗模式防止 Next.js 12 中的页面闪烁

use*_*025 15 javascript reactjs next.js tailwind-css

在 Tailwind CSS 中使用基于类的深色模式和 Next.js v12 时,如何防止页面闪烁,而不使用任何 3rd 方 pkg(例如 next-themes)?

我看过:

// On page load or when changing themes, best to add inline in `head` to avoid FOUC
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
    document.documentElement.classList.add('dark')
} else {
    document.documentElement.classList.remove('dark')
}
Run Code Online (Sandbox Code Playgroud)

Head我认为他们限制从 v12开始放入内容来为 Suspense / Streaming / React v18 做准备。

不管怎样,我不知道如何在没有下一个主题的情况下做到这一点,有谁知道我们如何注入那段脚本来防止页面闪烁?

希望这个问题有意义,如果没有,请给我留言。

我喜欢简单和简约的东西,因此目标是减少对第 3 方 pkgs 的依赖,这样一个简单的事情应该是可能的,而不需要过于复杂的解决方案 IMO。

Ron*_*thl 19

我遇到了同样的问题,并在 Next 12.1.0 中这样解决:

  1. theme.js在文件夹内创建public(我的有以下内容):
;(function initTheme() {
  var theme = localStorage.getItem('theme') || 'light'
  if (theme === 'dark') {
    document.querySelector('html').classList.add('dark')
  }
})()
Run Code Online (Sandbox Code Playgroud)
  1. 添加<Script src="/theme.js" strategy="beforeInteractive" />_app.tsx_app.jsx. 这很重要 - 我尝试将其放入其中_document.tsx但不起作用。最终_app.tsx效果如下:
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Head from 'next/head'
import Script from 'next/script'

function App({ Component, pageProps }: AppProps) {
  return <>
    <Head>
      <meta name="viewport" content="initial-scale=1.0, width=device-width" />
    </Head>
    <Script src="/theme.js" strategy="beforeInteractive" />
    <Component {...pageProps} />
  </>
}

export default App
Run Code Online (Sandbox Code Playgroud)

对我来说就像一个魅力 - 没有闪烁和所有 Next.js 的魔力。:) 希望这也适合你。


Fau*_*man 7

NextJS 13 与应用程序路由器:

直接查看 Twailwind 网站的页面源代码(通过单击 Chrome MacOS)后,我们可以看到他们正在使用他们在黑暗模式文档command+option+u中描述的确切策略。

然而,将此与NextJs 的内联脚本优化相结合将不起作用,因为它们将内联脚本的内容包装在对 next_js 的调用中,这最终要求页面在设置暗模式之前加载 NextJS(因此是 FOUC)。

为了避免这种情况,我们可以在根布局中使用script不进行优化的普通标签,并使用属性设置其内容,如下所示:dangerouslySetInnerHTML

<html lang="en" suppressHydrationWarning>
  <head>
    <script dangerouslySetInnerHTML={{
      __html: `
        try {
          if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
            document.documentElement.classList.add('dark')
          } else {
            document.documentElement.classList.remove('dark')
          }
        } catch (_) {}
      `
    }}/>

    {/* Other Meta Tags, Links, Etc... */}
  </head>
  
  <body className="text-slate-500 dark:text-slate-400 bg-white dark:bg-slate-900">
    {/* Content */}
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

这样,我们的脚本将是页面加载时首先执行的脚本之一,从而防止出现无样式内容。

[编辑]

Prop 'className' did not match当“dark”类存在于客户端 HTML 中但不存在于服务器渲染的 HTML 中时,此方法会导致 NextJS 在开发模式下引发警告。这是可以预料的,因为我们在 NextJS 有机会验证它之前就改变了 HTML 的结构。我们可以通过设置手动抑制警告suppressHydrationWarning我们可以通过在开始的 HTML 标签上

干杯!


归档时间:

查看次数:

6248 次

最近记录:

2 年,4 月 前