CSS変数によるクラスベースのダークモードトグル

HTML要素の.darkクラスを使用して、CSSカスタムプロパティのオーバーライドとlocalStorage永続化によるユーザー制御のダークモードトグルを実装します。

Dark Mode

詳細な説明

クラスベースのダークモードトグル

prefers-color-schemeは自動ですが、多くのアプリではユーザーに明示的な制御を与えたい場合があります。クラスベースのアプローチは<html>.darkクラスを追加し、CSS変数をオーバーライドします。

CSS構造

:root {
  --bg: #ffffff;
  --surface: #f4f4f5;
  --text: #18181b;
  --text-muted: #71717a;
  --primary: #2563eb;
  --border: #e4e4e7;
}

html.dark {
  --bg: #0a0a0b;
  --surface: #141415;
  --text: #fafafa;
  --text-muted: #a1a1aa;
  --primary: #3b82f6;
  --border: #27272a;
}

JavaScriptトグル

const toggle = document.getElementById('theme-toggle');
toggle.addEventListener('click', () => {
  document.documentElement.classList.toggle('dark');
  const isDark = document.documentElement.classList.contains('dark');
  localStorage.setItem('theme', isDark ? 'dark' : 'light');
});

誤ったテーマのフラッシュ防止

スタイルシートや本文コンテンツの前に<head>にブロッキングスクリプトを配置します:

<script>
  if (localStorage.getItem('theme') === 'dark' ||
      (!localStorage.getItem('theme') &&
       window.matchMedia('(prefers-color-scheme: dark)').matches)) {
    document.documentElement.classList.add('dark');
  }
</script>

フレームワーク統合

  • Next.js: SSR、ハイドレーション、フラッシュ防止を処理するnext-themesを使用。
  • Astro: ブロッキングチェック用にis:inlineスクリプトを使用。
  • プレーンHTML: 上記の<head>スクリプトがフレームワークなしで動作。

アクセシビリティ

トグルボタンにaria-labelを含め、現在の状態をアナウンスします。スクリーンリーダーに依存するユーザーは、トグルがライトモードとダークモードのどちらに切り替わるかを知る必要があります。

ユースケース

localStorageによる永続化を備えたユーザー向けダークモードトグルボタンが必要なアプリケーションで、フォールバックとしてOSレベルの設定検出と連携する場合。

試してみる — CSS Variable Generator

フルツールを開く