以下の要件をもとにダークモードを実装します。
- OSのダークモードと連動する。
- ページ遷移してもダークモードの設定が保存される。
- サイト側でもモードの切り替えができる。
- (理由1)ダークモードに対応していないデバイスが存在する。
- (理由2)OSはダークモードでもサイト側で切り替えたい場合がある
- CSS変数で管理する
要素を設置する
サイト側でモードを切り替えるチェックボックスを設置します。
<button class="c-button-switch" aria-label="カラーテーマ切り替え">
<input class="c-button-switch__input" id="js-switch-button" type="checkbox">
<label class="c-button-switch__label" for="js-switch-button"></label>
</button>
CSS変数でカラーの指定
通常のダークモード対応ではメディアクエリでprefers-color-scheme: dark
を指定しますが、今回はJavascriptでdata属性を使い動的に操作するので、CSSでは以下のように記述します。
/* ライトモード時 */
:root {
--color-base: #f1f5f9;
--color-primary: #000000;
--color-secondary: #eee;
}
/* ダークモード時 */
[data-mode="dark"] {
--color-base: #21242d;
--color-primary: #fff;
--color-secondary: #4B505E;
}
body {
background-color: var(--color-base);
color: var(--color-primary);
}
また、画像も背景がダークモードだと画像が粗く見えてしまうので、filter
などで彩度を下げたほうがいい場合もあります。
[data-mode='dark'] img {
filter: grayscale(20%);
}
JavaScriptで判定、切り替えを行う
OSがダークモードかどうか判定し、ダークモード時にhtmlタグへdata-mode="dark"
を動的に追加します。
チェックボックスで切り替えた際も同様にdata-mode="dark"
を追加し、その情報をsessionStorageへ保存し、タブを閉じるまで設定を保持させます。
localStorageにすれば永続的に保存することもできます。
以下MDNのWindow.localStorageから引用
localStorage
に保存されたデータには保持期間の制限はなく、sessionStorage
に保存されたデータはセッションが終わると同時に(ブラウザが閉じられたときに)クリアされてしまう
(function () {
const switchButton = document.getElementById('js-switch-button');
const isDark = window.matchMedia('(prefers-color-scheme: dark)');
const htmlElement = document.documentElement;
const keyLocalStorage = 'theme';
const localTheme = sessionStorage.getItem(keyLocalStorage);
if (localTheme) { // サイト側の設定が優先
changeMode(localTheme);
} else if (isDark.matches) { // OSがダークモードだったら
changeMode('dark');
}
switchButton.addEventListener('change', () => { // スイッチが押されたとき
if (switchButton.checked) {
changeMode('dark', 'set');
} else {
changeMode('light', 'set');
}
});
function changeMode(mode, storage) {
if (mode === 'dark') {
htmlElement.dataset.mode = mode;
switchButton.checked = true;
} else if (mode === 'light') {
delete htmlElement.dataset.mode;
switchButton.checked = false;
}
if (storage === 'set') {
sessionStorage.setItem(keyLocalStorage, mode);
} else if (storage === 'remove') {
sessionStorage.removeItem(keyLocalStorage);
}
}
}());
参考文献: ダークモード時のデザインについて
ダークモード時のデザインに関しては以下の記事が勉強になりました。