Next.jsで「ちらつき」のないダークモードを構築する
ダークモードの実装は簡単そうに見えます。しかし、あの「ちらつき」が発生します。
ユーザーがページを読み込む際、サーバーはデフォルトのテーマを送信します。ダークテーマが適用されるまでのほんの一瞬、ユーザーには白い画面が見えてしまいます。これはユーザー体験(UX)として良くありません。
この問題が発生する理由は、サーバーが localStorage を読み取ることができないからです。サーバーがテーマを認識できるのは、ブラウザで JavaScript が実行された後になります。
その解決策は以下の通りです。
解決策:インラインスクリプト
React が起動する前にテーマを適用する必要があります。<head> タグ内に小さなスクリプトを配置してください。このスクリプトが設定を読み取り、即座に dark クラスを追加します。
以下の手順で行います:
RootLayoutの<head>にlocalStorageをチェックするスクリプトを追加します。<html>タグにsuppressHydrationWarningを使用します。これにより、テーマの不一致に関する React の警告を防ぐことができます。ThemeProviderを使用して、状態の管理とlocalStorageとの同期を行います。- Tailwind と CSS 変数を使用して、色の遷移をスムーズにします。
なぜこれで解決するのか: スクリプトがページのレンダリング前に実行されるため、視覚的なちらつきを防ぐことができます。
画像の扱い
ライトモードとダークモードで異なる画像が必要になることがよくあります。選択肢は2つあります:
- CSS メソッド:
.darkクラスに基づいてdisplay: noneとdisplay: blockを使い分け、画像を切り替えます。これが最も高速な方法です。 - クライアントメソッド:テーマをチェックして適切な画像ソースを選択するコンポーネントを使用します。
サーバーサイドコンテンツ向けのプロのヒント
チャートや重いコンテンツのためにサーバー側でテーマを把握する必要がある場合は、localStorage の代わりにクッキー(cookies)を使用してください。
- テーマをクッキーに保存します。
- Next.js の middleware を使用してそのクッキーを読み取ります。
- ヘッダー経由でレイアウトにテーマを渡します。
これにより、サーバーは最初から正しい HTML を送信できるようになります。
ちらつきのないシステムのためのまとめ:
• <head> 内にインラインスクリプトを使用する
• suppressHydrationWarning を使用する
• Context Provider で状態を管理する
• システム設定の変更を監視する
このアプローチはプロダクション環境のアプリでも有効です。瞬時の切り替えを実現し、ちらつきをゼロにします。