🔦

Astro + daisyUIのサイトのダークモード対応

に公開

Astro + daisyUIで構築している自分のWebサイトをダークモード対応した際のメモ。

環境

package.json
{
  "dependencies": {
    "astro": "^5.9.2",
    "daisyui": "^5.0.43"
  }
}

テーマ切り替えUIの追加

まず、ライトモードとダークモードを切り替えるスイッチを追加。
daisyUIにはTheme Controllerというテーマ切り替え用コンポーネントが用意されているので、これを利用。

ダークモードのテーマはnightを採用。
ライトモードのテーマ:にはcorporateを使っていたが、corporatenightではスイッチの形状が異なり、切り替え時に違和感があったため、形状が近いwinterに変更。

ダークモード時の見た目調整

  • GitHubやXのSVGアイコンにfill-base-contentを指定し、暗色背景でも視認できるようにした
  • カードはshadowだけだと境界が見えづらくなるため、borderを追加

LocalStorageにテーマを保存

Theme Controllerはページ単位でしかテーマを切り替えられないため、画面遷移やリロードでデフォルトに戻ってしまう。 そこで、LocalStorageに選択したテーマを保存し、ロード時に反映する処理を追加した。LocalStorageに値がない場合、OSがダークモードならnightを適用するようにした。

今回はVanilla JSで実装したが、将来的にTypeScript化したい。

Header.astro
<script>
  const themeController = document.querySelector('.theme-controller');
  if (themeController) {
    const theme = (() => {
      if (
        typeof localStorage !== 'undefined' &&
        localStorage.getItem('theme')
      ) {
        return localStorage.getItem('theme');
      }

      if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
        return 'night';
      }

      return 'winter';
    })();

    const setTheme = (theme) => {
      document.documentElement.setAttribute('data-theme', theme);
      localStorage.setItem('theme', theme);
      if (themeController instanceof HTMLInputElement) {
        themeController.checked = theme === 'night';
      }
    };

    themeController.addEventListener('change', (e) => {
      const target = e.target;
      setTheme(target.checked ? 'night' : 'winter');
    });

    setTheme(theme);
  }
</script>

ちらつき対策

ダークモード時、画面遷移時に一瞬ライトモードが表示されるちらつきが発生。
原因はデフォルトモードの状態で描画されてからJSで切り替えているため。

MPAの性質上仕方ないと思っていたが、View Transitionを導入することで解消した。

  • ClientRouterを有効化
  • スイッチ状態を保持するため、input要素にtransition:persistを追加
  • astro:after-swapイベントでの再設定は不要だった(公式ドキュメントのケースは<script is:inline>の場合だから必要なんだと思うが、ちゃんと理解できていない)

まとめ

daisyUIのTheme Controllerを使って、ダークモードに対応した。
想定外だったMPAのちらつき問題は、View Transitionを導入して解消できた。
結果として、サイト全体のクオリティを向上できた。

ソースコード

https://github.com/nishitaku/portfolio/pull/73/files

Discussion