株式会社WR

株式会社WR

WEB TOTAL CONSULTING

Tailwind CSSでダークモードを実装する
ブログ一覧へ
技術ブログ

Tailwind CSSでダークモードを実装する

Tailwind CSS v3のdarkモードを使うと、class="dark"の追加だけでダークモードが切り替わるUIが実装できます。LocalStorageを使った設定保存も解説します。

ダークモードとは——現代UIの必須機能

ダークモードは、背景を暗くしてテキストを明るくするUIテーマです。目の疲れの軽減・バッテリー消費の削減(OLED端末)・視認性向上などのメリットから、macOS・iOS・Androidなど主要OSで標準サポートされています。

ユーザーがOSのダークモード設定をしている場合、Webサイトもそれに追従することで一貫したUXを提供できます。


Tailwind CSSのダークモード設定

Tailwind CSSには2つのダークモード戦略があります。

1. media(OS設定に連動)

// tailwind.config.js
module.exports = {
    darkMode: 'media', // prefers-color-scheme: dark に連動
    // ...
}
<!-- dark: プレフィックスで暗色時のスタイルを指定 -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
  <p>OS設定のダークモードに自動追従</p>
</div>

2. class(手動切り替え)

// tailwind.config.js
module.exports = {
    darkMode: 'class', // <html class="dark"> があれば暗色モード
    // ...
}

弊社では class 戦略を採用しています。ユーザーがボタンで切り替え、設定を localStorage に保存することで次回訪問時も維持できます。


トグルボタンの実装

<!-- ダークモード切り替えボタン -->
<button
    id="theme-toggle"
    class="p-2 rounded-full bg-gray-100 dark:bg-gray-800
           text-gray-600 dark:text-gray-300
           hover:bg-gray-200 dark:hover:bg-gray-700
           transition-colors duration-200"
    aria-label="ダークモード切り替え"
>
    <!-- 太陽アイコン(ライトモード時に表示) -->
    <svg id="icon-sun" class="w-5 h-5 hidden dark:block" fill="currentColor" viewBox="0 0 20 20">
        <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0z" clip-rule="evenodd"/>
    </svg>
    <!-- 月アイコン(ダークモード時に表示) -->
    <svg id="icon-moon" class="w-5 h-5 block dark:hidden" fill="currentColor" viewBox="0 0 20 20">
        <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/>
    </svg>
</button>

JavaScriptでの切り替えロジック

// テーマの初期化(ページ読み込み時)
function initTheme() {
    const savedTheme = localStorage.getItem('theme');
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

    if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
        document.documentElement.classList.add('dark');
    } else {
        document.documentElement.classList.remove('dark');
    }
}

// テーマの切り替え
function toggleTheme() {
    const isDark = document.documentElement.classList.toggle('dark');
    localStorage.setItem('theme', isDark ? 'dark' : 'light');
}

// ボタンにイベント設定
document.getElementById('theme-toggle').addEventListener('click', toggleTheme);

// 初期化(<head>内でも呼ぶとFOUC防止に効果的)
initTheme();

FLASHを防ぐ——FOUC対策

ページ読み込み時に一瞬ライトモードが表示されてからダークモードに切り替わる「FOUC(Flash of Unstyled Content)」を防ぐには、<head> 内で早期にクラスを設定します。

<head>
    <meta charset="UTF-8">
    <!-- ダークモード初期化スクリプト(他より先に実行) -->
    <script>
        (function() {
            const theme = localStorage.getItem('theme');
            const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
            if (theme === 'dark' || (!theme && prefersDark)) {
                document.documentElement.classList.add('dark');
            }
        })();
    </script>
    <!-- 以降のcssやJSはここに -->
</head>

カラーパレットの設計

ダークモードに対応したカラーパレットを tailwind.config.js で定義します。

module.exports = {
    darkMode: 'class',
    theme: {
        extend: {
            colors: {
                // ライト/ダーク共通のセマンティックカラー
                surface: {
                    DEFAULT: '#ffffff',
                    dark:    '#1a1a2e',
                },
                'on-surface': {
                    DEFAULT: '#1c1c1c',
                    dark:    '#e8e8e8',
                },
                primary: {
                    DEFAULT: '#d4b896',
                    dark:    '#c9a97a',
                },
            },
        },
    },
}

コンポーネント全体での統一的な適用

<!-- カード コンポーネント例 -->
<div class="
    bg-white dark:bg-gray-800
    border border-gray-200 dark:border-gray-700
    rounded-xl shadow-sm
    p-6
    transition-colors duration-200
">
    <h3 class="text-gray-900 dark:text-gray-100 font-bold text-lg">
        タイトル
    </h3>
    <p class="text-gray-600 dark:text-gray-400 text-sm mt-2 leading-relaxed">
        説明テキスト
    </p>
    <a href="#"
       class="text-amber-700 dark:text-amber-400 hover:underline text-sm font-medium">
        詳しく見る →
    </a>
</div>

Alpine.jsとの組み合わせ

Alpine.jsを使うとよりリアクティブな実装ができます。

<div
    x-data="{ dark: localStorage.getItem('theme') === 'dark' }"
    x-init="$watch('dark', val => {
        document.documentElement.classList.toggle('dark', val);
        localStorage.setItem('theme', val ? 'dark' : 'light');
    })"
    :class="{ 'dark': dark }"
>
    <button @click="dark = !dark" class="p-2 rounded">
        <span x-show="!dark">🌙</span>
        <span x-show="dark">☀️</span>
    </button>
</div>

まとめ

Tailwind CSSのダークモードは dark: プレフィックスで直感的に実装でき、JavaScriptとlocalStorageを組み合わせることで、ユーザー設定を保持した切り替え機能を実現できます。弊社では新規プロジェクトでは標準的にダークモード対応を実施しています。

Webサイト・アプリのUI開発についてはお気軽にご相談ください。

Category 技術ブログ

Related Posts

関連記事

開発・技術のご相談はお気軽に

お見積りは無料です。まずはお気軽にご相談ください。

お問い合わせ →