Tailwindcssでダークモードを動的に適用する方法

Tailwindcssにはダークモードが搭載されています。

筆者もダークモード愛用者なので、これは嬉しいところ。

HTML
<html class="dark">
...
</html

上記のように、HTMLの先頭のクラスに dark を指定するだけでダークモードが適用されます。

でも、人によってはライトモードの方が好き!という方のためにも、

どちらにも対応できるようにボタンで切り替えて動的にモード変更出来るようにしていきます。

目次

何故かダークモードが適用できない

公式ドキュメントを参照すると

CSS(input.css)
@custom-variant dark (&:where(.dark, .dark *));

上記のCSSをinput.cssに入れます。

(公式ドキュメントに合わせてinput.cssにしていますが、他の名前でも大丈夫です)

そして

Bash
npx @tailwindcss/cli -i ./input.css -o ./output.css

のbashを叩けば適用されるらしいです。

やってみたけれど・・・適用されません(泣)

環境の問題なのかもしれないですが、私の環境では適用されませんでした。

[data-]属性でダークモードに切り替える

公式に記載されているクラスではなく、[data-]属性を使えば動かすことが出来ました。

CSS(input.css)
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
HTML
<html data-theme="" class="bg-gray-100 dark:bg-black">
...
</html>

公式の方法とは違うけれど、これでとりあえずモード切替の準備が出来ました。

ボタンが押下されたらモードを切り替える

動的に変えるということは、JavaScriptが必須です。

その前に適当にボタンを作っておきます。

HTML
    <!-- 現在ダークテーマ -->
    <button id="button-dark" class="right-0 float-right" onClick="toggleTheme()">
        明るくするよ
    </button>

    <!-- 現在ライトテーマ -->
    <button id="button-light" class="right-0 float-right" onClick="toggleTheme()">
        暗くするよ
    </button>

2つボタンを作って、一方のボタンだけ表示するという体で作っています。

次はonClickに書いたJavaScriptです。

JavaScript
// HTMLのdata-themeを差し替え
function toggleTheme() {
  const current = document.documentElement.getAttribute('data-theme');
  const next = current === 'dark' ? 'light' : 'dark';
  document.documentElement.setAttribute('data-theme', next);
  localStorage.setItem('theme', next);

  setButton(next);
}

// ボタンを差し替え
function setButton(theme){

  const next_id = theme === 'dark' ? "button-dark" : "button-light";
  const before_id = theme === 'dark' ? "button-light" : "button-dark";
  const next_button = document.getElementById(next_id);
  const before_button = document.getElementById(before_id);

  next_button.classList.remove('hidden');
  next_button.classList.add('inline-block');
  before_button.classList.remove('inline-block');
   before_button.classList.add('hidden');

  //コンテナの色も変更
  const containers = document.querySelectorAll(".container");
  if (!containers) return;
  containers.forEach(item => {
    item.classList.toggle("bg-black",theme === "dark");
  });
}

setButtonに書いたコードが汚いですがお許しを(汗)

これで、ボタンがクリックされたら、もう一方のボタンを表示させて、

テーマを変更するというロジックが出来ました。

何故かわかりませんが、コンテナの色が変わらないので、ここで一緒に変更しています(汗)

デフォルトのテーマの取得+ローカルストレージに保存

ボタンをクリックされた時にテーマを変更されるロジックはできたけれど、

ユーザーのデフォルトテーマを取得して、サイトに初めてアクセスした時は、

それを適用するようにロジックを追加していきましょう。

また、現在表示されているテーマをローカルストレージに保存して、

次にアクセスした時はその値からどちらのテーマを初期表示するかを判定します。

JavaScript
//テーマを変更
function setTheme(theme) {
  document.documentElement.setAttribute('data-theme', theme);
  localStorage.setItem('theme', theme);
}

//テーマを初期化
function initTheme() {
  const saved = localStorage.getItem('theme');
  const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  const theme = saved || (prefersDark ? 'dark' : 'light');
  setTheme(theme);

 //ボタンを差し替え
  setButton(theme);
}

initTheme();

DevToolで確認すると theme に値がセットされているのが確認できました。

これで完成です。

実際にやってみて

ダークモードが適用された時は、かなり感動的でした。

私自身がダークモードが好きなので、これが適用できたのは、とても嬉しかったです。

他にもダークモードの方が目に優しいから好きという方もいらっしゃるかと思うので、実装出来てよかったです。

また、これを動的に切り替えることが可能なので、ユーザーフレンドリーな作りに出来たかなと思います。

まとめ

・ダークモードを適用するなら通常 <html class=”dark”> で動く
・上記で動かない場合は[data-]属性を使用する
・JavaScriptでダークテーマ、ライトテーマの切り替えを行う
・次回アクセスした時のためにローカルストレージにテーマを保存する

ダークモードの実装って難しそう?って思っている初心者の方も、思ったよりも簡単に実装できるので、是非やってみてください。

  • URLをコピーしました!
目次