Next.jsで「ちらつき」のないダークモードを構築する

ダークモードの実装は簡単そうに見えます。しかし、あの「ちらつき」が発生します。

ユーザーがページを読み込む際、サーバーはデフォルトのテーマを送信します。ダークテーマが適用されるまでのほんの一瞬、ユーザーには白い画面が見えてしまいます。これはユーザー体験(UX)として良くありません。

この問題が発生する理由は、サーバーが localStorage を読み取ることができないからです。サーバーがテーマを認識できるのは、ブラウザで JavaScript が実行された後になります。

その解決策は以下の通りです。

解決策:インラインスクリプト

React が起動する前にテーマを適用する必要があります。<head> タグ内に小さなスクリプトを配置してください。このスクリプトが設定を読み取り、即座に dark クラスを追加します。

以下の手順で行います:

  • RootLayout<head>localStorage をチェックするスクリプトを追加します。
  • <html> タグに suppressHydrationWarning を使用します。これにより、テーマの不一致に関する React の警告を防ぐことができます。
  • ThemeProvider を使用して、状態の管理と localStorage との同期を行います。
  • Tailwind と CSS 変数を使用して、色の遷移をスムーズにします。

なぜこれで解決するのか: スクリプトがページのレンダリング前に実行されるため、視覚的なちらつきを防ぐことができます。

画像の扱い

ライトモードとダークモードで異なる画像が必要になることがよくあります。選択肢は2つあります:

  • CSS メソッド.dark クラスに基づいて display: nonedisplay: block を使い分け、画像を切り替えます。これが最も高速な方法です。
  • クライアントメソッド:テーマをチェックして適切な画像ソースを選択するコンポーネントを使用します。

サーバーサイドコンテンツ向けのプロのヒント

チャートや重いコンテンツのためにサーバー側でテーマを把握する必要がある場合は、localStorage の代わりにクッキー(cookies)を使用してください。

  • テーマをクッキーに保存します。
  • Next.js の middleware を使用してそのクッキーを読み取ります。
  • ヘッダー経由でレイアウトにテーマを渡します。

これにより、サーバーは最初から正しい HTML を送信できるようになります。

ちらつきのないシステムのためのまとめ:

<head> 内にインラインスクリプトを使用する • suppressHydrationWarning を使用する • Context Provider で状態を管理する • システム設定の変更を監視する

このアプローチはプロダクション環境のアプリでも有効です。瞬時の切り替えを実現し、ちらつきをゼロにします。

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