1
2

【JavaScript】ダークモードの切り替えボタン

Last updated at Posted at 2022-09-10

ダークモード始めましたか?

エディターをダークモードにしたのがきっかけで、OS、アプリとダークモード始めました!
ダークモードに慣れてしまうと、ダークモード非対応のサイトがめっちゃ眩しい…:persevere:

というわけで、ユーザーの好みに応じてサイトのカラーモードを切り替えられるボタンを作ってみました!

ちなみに…
私はドラキュラテーマの大ファンです。
エディターだけかと思ったら、たくさんのアプリにも対応してくれています。
いっそのことWindowsのOS自体も対応してほしい!

以下のアプリにドラキュラテーマを適用しています。

  • Visual Studio Code
  • Chrome
  • Firefox
  • Thunderbird
  • Slack

FileZilla にも対応してくれないかな…

仕様

ブラウザを開いてる間変更したカラーモードを保存するため、セッションストレージを利用します。

  • ページ読み込み時のカラーモード
    • セッションストレージなし
      • OSのカラーモード
    • セッションストレージあり
      • OSのカラーモードから反転
  • 切り替えボタンをクリック
    • OSのカラーモードと異なる
      • html 要素に反転用の class を付与
      • セッションストレージに反転用の値を保存
    • OSのカラーモードと同じ
      • html 要素に反転用の class が付与されていたら削除
      • セッションストレージに反転用の値が保存されていたら削除
  • OSのカラーモードを変更
    • html 要素に反転用の class が付与されていたら削除
    • セッションストレージに反転用の値が保存されていたら削除

HTML

ページ読み込み時、セッションストレージの判定を行う必要があります。
これはページが描画される前に行わないと、OSのカラーモードが一瞬チラついてしまいます。
そのため、head 要素のなるべく上のほうに記述し、実行させます。

HTML
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, viewport-fit=cover">
    <meta name="color-scheme" content="light dark">
    <script>
      // セッションストレージの判定を行う
      if (sessionStorage.getItem('colorMode') === 'invert') {
        const colorMode = sessionStorage.getItem("colorMode");
        document.documentElement.classList.add(colorMode)
      }
    </script>
  </head>
  <body>
    ...
  </body>
</html>

Sass

@mediaprefers-color-scheme メディア特性でライトとダークの時の設定をします。
html 要素に反転用の class が付与された時の設定もします。
また、切り替えボタンのアイコンの変更も、反転用の class を継承して設定します。

Sass
@mixin light-colors {
  --color: #333;
  --bg-color: #fff;
}
@mixin dark-colors {
  --color: #f2f2f2;
  --bg-color: #282a36;
}
@media (prefers-color-scheme: light) {
  :root {
    @include light-colors;
    .btn {
      &::before {
        content: "\f185";
      }
    }
    &.invert {
      @include dark-colors;
      .btn {
        &::before {
          content: "\f186";
        }
      }
    }
  }
}
@media (prefers-color-scheme: dark) {
  :root {
    @include dark-colors;
    .btn {
      &::before {
        content: "\f186";
      }
    }
    &.invert {
      @include light-colors;
      .btn {
        &::before {
          content: "\f185";
        }
      }
    }
  }
}
body {
  background-color: var(--bg-color);
}
.btn {
  color: var(--color);
  &::before {
    font-family: "Font Awesome 6 Free";
  }
}

JavaScript

JS
class ColorModeToggleButton {
  #colorModeMql
  #colorModeBtn
  #strageKey
  #strageVal
  constructor() {
    this.#colorModeMql = window.matchMedia('(prefers-color-scheme: dark)')
    this.#colorModeBtn = document.getElementById('js-colorModeBtn')
    this.#strageKey = 'colorMode'
    this.#strageVal = 'invert'
    this.#init()
  }

  #init() {
    this.#changeOsColorMode()
    this.#clickColorModeBtn()
  }

  // OSのカラーモードから反転
  #invertColorMode() {
    sessionStorage.setItem(this.#strageKey, this.#strageVal)
    document.documentElement.classList.add(this.#strageVal)
  }

  // OSのカラーモードに戻す
  #resetColorMode() {
    sessionStorage.removeItem(this.#strageKey)
    document.documentElement.classList.remove(this.#strageVal)
  }

  // OSのカラーモードの切り替え
  #changeOsColorMode() {
    this.#colorModeMql.addEventListener('change', () => {
      // セッションストレージが設定されている場合は削除(OSの設定優先)
      if (sessionStorage.getItem(this.#strageKey)) {
        this.#resetColorMode()
      }
    })
  }

  // カラーモードボタンをクリック
  #clickColorModeBtn() {
    this.#colorModeBtn.addEventListener('click', () => {
      sessionStorage.getItem(this.#strageKey)
        ? this.#resetColorMode()
        : this.#invertColorMode()
    })
  }
}
const colorModeToggleButton = new ColorModeToggleButton();

DEMO

See the Pen Dark Mode Toggle Button by Takuya Mori (@taqumo) on CodePen.

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2