ダークモード
2022年1月25日
みなさんこんにちは。
ケミストのWeb担当みやのです。
「Web」記事では、これまでに得たWebに関する知識を記録として残していきたいと思います。
さて今回は「ダークモード」を実装した時の様子をお伝えします。
参考:Webクリエイターボックス|Webサイトをダークモードに対応させよう
ダークモードとは
ダークモード(ダークテーマ)とは、黒背景・白文字を基調とした画面の配色のことです。
iPhoneやAndroidの端末で設定したり、ソフトやアプリで設定したりできます。
ダークモードのメリットは、
・目に優しい
・見やすい
・有機ELで消費電力が40%減る
・ブルーライトが減る
・集中力が高まる
だそうです(ホンマかいな)
端末の設定に対応
CSSで以下の設定をします。
:root {
--main-text: #333;
--main-bg: #fff;
}
@media (prefers-color-scheme: dark) {
:root {
--main-text: #ddd;
--main-bg: #000;
}
}
body {
color: var(--main-text);
background-color: var(--main-bg);
transition: .3s;
}
通常時は
文字色 背景色
ダークモードでは
文字色 背景色
になります。
--〇〇 はCSS変数(カスタムプロパティ)というらしいです。勉強になります!
これでだいたいOKなのですが、気になる部分には以下のCSSを追加します。
color: inherit;
background-color: transparent;
inheritは「継承」という意味で、親要素の属性値を引き継ぐ効果があります。
transparentは「透明」を意味します。
切り替えスイッチ実装
サイト上でダークモードのオンオフができるようにしたいと思います。
まずはCSSでライトモード、ダークモードのスタイルを設定します。
.light-theme {
background: #fff;
color: #333;
}
.dark-theme {
background: #000;
color: #ddd
}
JavaScriptで、ダークモードならdark-theme、そうでないならlight-themeを<body>に対して付与します。
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const darkModeOn = darkModeMediaQuery.matches;
darkModeMediaQuery.addListener((e) => {
const darkModeOn = e.matches;
if (darkModeOn) {
document.body.classList.remove('light-theme');
document.body.classList.add('dark-theme');
} else {
document.body.classList.remove('dark-theme');
document.body.classList.add('light-theme');
}
});
constが定数で、ifとelseが命令文です。たぶん。
前回作ったトグルスイッチを使います。
<div class="toggle_switch">
<input id="btn-mode" type="checkbox" value=""><label for="btn-mode"></label>
</div>
トグルスイッチにbtn-modeというIDを設定します。
const btn = document.querySelector("#btn-mode");
btn.addEventListener("change", () => {
if (btn.checked == true) {
document.body.classList.remove("light-theme");
document.body.classList.add("dark-theme");
} else {
document.body.classList.remove("dark-theme");
document.body.classList.add("light-theme");
}
});
チェックボックスにチェックが入っていれば(=スイッチがオンならば)dark-theme、そうでないならlight-themeが<body>に対して付与されます。
これでパウっと解決!ワンダフル!のはずでしたが...
誤算
トグルスイッチを左のメニューの下に設置すると、なぜか勝手にオンになってしまいます。
スイッチの見た目だけの問題なので、端末でダークモードを設定していないなら画面はライトモードです。つまり、
①スイッチはオンだが画面はライトモード
②スイッチオフ→ライトモードのまま
③再度スイッチオン→ダークモードになる
という状況になってしまいました。
checkedを入れなければ、初期状態ではオフのはずなのに...
なにジョジョ?
トグルスイッチが
オフにならない?
ジョジョ それは
無理矢理オフにしようと
するからだよ
逆に考えるんだ
「オンのままでいいさ」と
考えるんだ
と、ジョースター卿もおっしゃっていました。何とかしましょう。
解決法その①
このスイッチは「ライトモードのオンオフスイッチ」だと思うことにします。
ただ、見た目的には「ダークモードのオンオフスイッチ」にしたいので、オンとオフの見た目を逆にしてごまかします。
さっきのJavaScriptのifとelseの内容を逆にします。
btn.addEventListener("change", () => {
if (btn.checked == true) {
document.body.classList.remove("dark-theme");
document.body.classList.add("light-theme");
} else {
document.body.classList.remove("light-theme");
document.body.classList.add("dark-theme");
}
});
チェックされていればlight-theme、そうでなければdark-themeが適用されます。
トグルスイッチのオンとオフの見た目を入れ替えます。
.toggle_switch > label {
background-color: #2dcb45;
}
.toggle_switch > input:checked + label {
background-color: #2b2a2f;
}
.toggle_switch > label::before {
left: 0.9em;
}
.toggle_switch > input:checked + label::before {
left: 0.1em;
}
オフの見た目がオンの見た目がになります(ややこしい)
一応これで意図した挙動になりましたが、ページ読み込み時に一瞬スイッチがオン→オフ(内部的にはオフ→オン)になるのがモヤっとします。
解決法その②
メニューにトグルスイッチを複数設置した場合はどうなるかというと、勝手にオンになるのは最初の1つだけと判明しました。マジかよ...
というわけで1つめにダミーのスイッチを設置してd-noneで非表示にして、2つめに本命のトグルスイッチを設置します。
<div class="d-none"><input id="dummy" type="checkbox" value=""></div>
<div class="toggle_switch">
<input id="btn-mode" type="checkbox" value=""><label for="btn-mode"></label>
</div>
この方法でうまくいきました!
まとめ
まだ解決できていない問題があります。
・端末でダークモードに設定していると、ハンバーガーメニューが黒いままなので背景に溶け込んで見えない
・モードに関わらずスイッチは初期状態
なんでかなあ。今後の課題とします。
ブルーライトがカットされてる!
ダークモードで世界が変わる!