ダークモード入門
はじめに
WEBサイトにダークモードを実装する際に調べたことの覚書です。
以下のような内容です。
- OSの設定によってCSSのメディアクエリでスタイルを適用する
- 切り替えスイッチによるモードの変更
- おまけ:Tailwind CSSでダークモード
今回作成したコードの全体は以下になります。
CSSのメディアクエリでスタイル適用する
最初に、OSで設定されたモードによって、CSSのメディアクエリprefers-color-scheme
で適用するスタイルを切り替える方法です。:root
に変数で色を指定して利用しています。
:root {
--cBackground: #fedfe1;
--cText: #656765;
}
/* OSの設定がダークモード時のスタイル */
@media (prefers-color-scheme: dark) {
:root {
--cBackground: #64363c;
--cText: #fcfaf2;
}
}
.test {
width: 100px;
height: 100px;
margin: 0 auto;
background-color: var(--cBackground);
}
.test__text {
color: var(--cText);
text-align: center;
line-height: 100px;
}
この状態でOSのモードを切り替えるとスタイルが切り替わります。
OSのモード切替
OSのモード切替方法は、windows10の場合 [設定 > 個人設定] から色
の規定のアプリモードを選択します
から切り変えられます。
また、ブラウザの開発ツールでエミュレートすることもできます。
-
Chrome
メニューから[More tools > Rendering]で「Emulate CSS media feature prefers-color-scheme」でモードを選択します。
-
Firefox
「インスペクター」の「ルール」内のアイコンでモードの切り替えができます(旧バージョンでは設定方法とアイコンが変わっているかもしれません。今回は"88.0.1"を使用しています)。
切り替えスイッチによるモードの変更
次に切り替えスイッチを設置して、UI上でモードの切替を行えるようにします。
まず、OSのモード設定をJavaScriptのmatchMedia
を利用してメディアクエリprefers-color-scheme
の値で判定して、ルート要素<html>にクラスの追加・削除をします。イベントリスナーから変更を検知しています。
// OSの設定がダークモード
const osDark = window.matchMedia("(prefers-color-scheme: dark)");
// ダークモードがオンの時に実行する処理
function darkModeOn() {
document.documentElement.classList.add("darkmode"); // ルート要素<html>にクラスを追加
}
// ダークモードがオフの時に実行する処理
function darkModeOff() {
document.documentElement.classList.remove("darkmode"); // クラスの削除
}
// イベントリスナー
const listener = (event) => {
if (event.matches) {
darkModeOn();
} else {
darkModeOff();
}
};
// リスナー登録
osDark.addEventListener("change", listener);
// 初期化処理
listener(osDark);
matchMedia
の記述についてはこちらの記事を参考にさせて頂きました。(ありがとうございます!)
ダークモード用のクラス.darkmode
を記述します。
:root {
--cBackground: #fedfe1;
--cText: #656765;
}
/* OSの設定がダークモード時のスタイル */
:root.darkmode {
--cBackground: #64363c;
--cText: #fcfaf2;
}
...
これで先程の「CSSのメディアクエリでスタイル適用する」と同様にOSの設定によってスタイルが切り替えられるようになりました。
切り替えボタンの設置
次に切り替えボタンを設置します。今回は以下のツールを使用して簡単に作成しています。
作成されたhtmlを貼り付けて使用します。...
<!-- 切り替えスイッチ -->
<div class="onoffswitch">
<input
type="checkbox"
name="onoffswitch"
class="onoffswitch-checkbox"
id="myonoffswitch"
tabindex="0"
/>
<label class="onoffswitch-label" for="myonoffswitch">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
...
スイッチにふられたIDから要素を取得して、チェックボックスのオンオフに応じてスタイルを切り替えます。
// ...
// スイッチのinput要素(checkbox)
const modeSwitch = document.getElementById("myonoffswitch");
// ...
// スイッチの操作に応じて切り替え処理
modeSwitch.addEventListener("change", () => {
if (modeSwitch.checked) {
darkModeOn();
} else {
darkModeOff();
}
});
これでスイッチでモードの切替ができるようになりました。
スイッチとモードを一致させる
現状OSの設定がダークモードになっていた場合に、初回ロードでページ表示はダークモード、スイッチはライトモードとちぐはぐな状態となってしまいます。
そこで、以下のようにモード切り替え関数に追記してスイッチとモードを一致させます。
// ...
function darkModeOn() {
document.documentElement.classList.add("darkmode");
+ modeSwitch.checked = true;
}
function darkModeOff() {
document.documentElement.classList.remove("darkmode");
+ modeSwitch.checked = false;
}
これでOSの設定がダークモードの場合はスイッチもDarkになるようになりました。
スイッチの状態をブラウザーで保持する
最後に、スイッチの状態を保持できるようにしてみます。
現状スイッチでモードを切り替えた後にページをリロードするとOSの設定に戻ってしまいます。ブラウザのストレージを利用してこれに対応します。
ブラウザのストレージはlocalStorage
とsessionStorage
がありますが、今回はセッションが持続する間だけ状態を保持するようにsessionStorage
を使用しました。
// ...
// スイッチの操作に応じて切り替え処理
modeSwitch.addEventListener("change", () => {
if (modeSwitch.checked) {
darkModeOn();
+ sessionStorage.setItem("darkMode", "on");
} else {
darkModeOff();
+ sessionStorage.setItem("darkMode", "off");
}
});
+// ロード時の状況に応じて切り替え
+if (sessionStorage.getItem("darkMode") === "on") {
+ darkModeOn();
+} else if (sessionStorage.getItem("darkMode") === "off") {
+ darkModeOff();
+}
sessionStorage.setItem("key", "value")
の形でkey
にdarkMode
、valu
にはスイッチの操作によってon
/off
をセットしています。
そして、ページロード時にsessionStorage.getItem("darkMode")
でdarkMode
の値を確認してon
/off
それぞれの処理を行うようにします。
これでページをリロードしても、スイッチとモードの状態が保持されるようになりました。
Tailwind CSSでダークモードを使う
最後におまけとしてTailwind CSSでダークモードの設定をしてみます。
Tailwind CSSの導入については公式に詳しく書かれていますので省略します。(私も以前に導入について少し書いてみたので、参考にしてもらえたら嬉しいです)
OSの設定によってモードの切り替え
OSの設定によってモードを切り替える場合、Tailwind CSSの"v2"からは設定ファイル(tailwind.config.js)にdarkMode
の設定をmedia
とするだけで利用できます。
module.exports = {
purge: [],
- darkMode: false, // or 'media' or 'class'
+ darkMode: 'media',
// ...
};
これで擬似クラス(variants)に"dark"が追加さるので、dark:
でダークモード時のクラス定義ができるようになります。
以下のように記述すると「sample-01」と同じようにスタイルがあたります。
...
<div class="mt-[6px] mx-auto w-[100px] h-[100px] bg-[#fedfe1] dark:bg-[#64363c]">
<div class="text-center leading-[100px] text-[#656765] dark:text-[#fcfaf2]">
test-03
</div>
</div>
...
手動でのモードの切替
手動でモードの切替を行う場合は、tailwind.config.js
のdarkMode
をclass
にします。
module.exports = {
purge: [],
- darkMode: 'media',
+ darkMode: 'class',
// ...
};
これでdark
クラスが先祖要素に付与されている場合にダークモードが適用されます。
以下の公式ドキュメントを参考に、ボタンを設置して切り替えができるようにしてみました。
...
<!-- 切り替えボタン -->
<button
id="toggleButton"
class="block w-[100px] h-[40px] mx-auto rounded-md hover:opacity-90 bg-[#64363c] text-[#fcfaf2] dark:bg-[#fedfe1] dark:text-[#656765]"
>
change
</button>
...
// 初期化(OSの設定によってモードとsessionStorageを設定)
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark')
sessionStorage.theme = 'dark';
} else {
document.documentElement.classList.remove('dark')
sessionStorage.theme = 'light';
}
// ボタン要素のクリックイベント
const toggleButton = document.getElementById('toggleButton');
toggleButton.addEventListener("click", () => {
toggleDarkMode();
})
// モードとsessionStorageの切り替え関数
const toggleDarkMode = () => {
if (sessionStorage.theme === 'dark') {
document.documentElement.classList.remove('dark')
sessionStorage.theme = 'light';
} else {
document.documentElement.classList.add('dark')
sessionStorage.theme = 'dark';
}
}
ボタンで切り替えができるようになりました。
おわりに
以上が今回ダークモードについて調べた内容です。
以前GitHubのUI上でネコのイラストの切り替えスイッチがあったと思うのですが、それが好きだったのでなくなってしまった時とても残念でした(さよなら~みたいなアニメーション付きで去っていった気がします...)。
その時に自分でもダークモードを実装してみたいなと思うようになり、今回記事にしてみました。参考になれば幸いです!
また、内容に誤り等ありましたらご指摘いただけるとありがたいです。
Discussion