JavaScript

ダークモードをCSSとJavaScriptで実装する方法

JavaScript

ダークモードをCSSとJavaScriptで実装する方法

ダークモードとはWebサイトや、アプリなどの背景色を黒基調としたものです。
長時間画面を眺める場合は、ダークモードの方が目に優しいと言われていますので、制作者の私もダークモード設定ができるWebサービスは、全てダークモードにしています。

今回はOS側でダークモードにした際のWebサイトの設定方法と、ユーザーが任意でダークモードを選択できる方法をご紹介します。

OS側の設定をWebサイトに反映する方法

ダークモードをCSSとJSで実装する方法

Macの場合「システム環境設定」から「一般」を選択して、外観モードから「ライト」「ダーク」を選択することができます。
このOS設定の判定方法は、CSSのメディアクエリを使う方法と、JavaScriptを用いる方法があります。

CSSのメディアクエリ

@media (prefers-color-scheme: dark) {
	body {
		color: #fff;
		background: #000;
	}
}

上記の「@media (prefers-color-scheme: dark)」の内側に、ダークモードにするCSSのプロパティを設定することで、簡単に適用することができます。

CSS変数でカラーを管理すると便利

/*ライトモードの場合は、次の変数が適用される*/
:root {
	--main-text: #000;
	--main-bg: #fff;
}
/*ダークモードの場合は、次の変数が適用される*/
@media (prefers-color-scheme: dark) {
	:root {
		--main-text: #fff;
		--main-bg: #202124;
	}
}
body {
	color: var(--main-text);
	background: var(--main-bg);
}

ダークモードのプロパティを各要素に細かく設定すると管理が面倒になってきます。
CSS変数を使うことで、カラーの管理がやりやすくなります。

CSSの設定方法は以上となります。

JavaScriptで外観モードを判定する方法

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-mode');
        document.body.classList.add('dark-mode');
    } else {
        document.body.classList.remove('dark-mode');
        document.body.classList.add('light-mode');
    }
});

if文を用いてダークモードか判定しています。
ダークモードであればbody要素に「dark-mode」クラスを付与しており、ライトモードであれあばbody要素に「light-mode」クラスを付与しています。

ユーザーが任意でダークモードを選択する場合

See the Pen by RECOOORD (@recooord) on CodePen.

上記のチェックボックスを選択してみてください。モードが切り替わるのが確認できたと思います。

チェックボックスの判定について

const btn = document.querySelector("#btn-dark-mode");

//チェックボックス切り替え判定
btn.addEventListener("change", () => {
	if (btn.checked === true) {
		document.body.classList.remove('light-mode');
		document.body.classList.add('dark-mode');
	}else {
		document.body.classList.remove('dark-mode');
		document.body.classList.add('light-mode');
	}
});

ユーザーが任意でモードを切り替える場合はチェックボックスを使います。
JavaScriptでは、チェックボックスにチェックが入っているのかを判定をして、bodyにクラスを付与しています。

しかし上記のコードだとページ遷移した場合に、ダークモードはリセットされています。
次に紹介するJavaScriptのローカルストレージを使うことで、ページを遷移しても選択したモードは適用されたままになります。

ローカルストレージを適用した場合

const btn = document.querySelector("#btn-dark-mode");

//チェックボックス切り替え判定
btn.addEventListener("change", () => {
	if (btn.checked === true) {
		document.body.classList.remove('light-mode');
		document.body.classList.add('dark-mode');
		localStorage.setItem('dark-mode-settings', 'dark');
	}else {
		document.body.classList.remove('dark-mode');
		document.body.classList.add('light-mode');
		localStorage.setItem('dark-mode-settings', 'light');
	}
});
	
//ローカルストレージ判定
if(localStorage.getItem('dark-mode-settings')==='dark') {
	document.body.classList.add('dark-mode');
	btn.checked = true;
}else if (localStorage.getItem('dark-mode-settings')==='light') {
	document.body.classList.add('light-mode');
}

チェックボックスの切り替え判定に、ローカルストレージのコードを追加しました。
上記のコードにすることで、ページを遷移しても選択したモードは適用されたままになります。

OS側の設定も考慮して、Webサイトでも任意にモードを選択したい場合

See the Pen by RECOOORD (@recooord) on CodePen.

上記のサンプルでは、OS側でモードの設定もできるし、Webサイト側でもモードを選択できる方法になります。

CSSの解説

:root {
	--main-text: #000;
	--main-bg: #fff;
}
@media (prefers-color-scheme: dark) {
	:root {
		--main-text: #fff;
		--main-bg: #202124;
	}
}
body{
  color: var(--main-text);
  background: var(--main-bg);
  transition: .3s;
}
.light-mode{
  --main-text: #000;
  --main-bg: #fff;
}
.dark-mode{
  --main-text: #fff;
  --main-bg: #202124;
}

メディアクエリの「@media (prefers-color-scheme: dark) 」で、OS側のモードを判定し、カラーを指定してます。
bodyタグのCSSに付与するカラーは変数で管理してます。

JavaScriptの解説

const btn = document.querySelector("#btn-dark-mode");

//OS側の設定判定
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-mode');
        document.body.classList.add('dark-mode');
        localStorage.setItem('dark-mode-settings', 'dark');
    } else {
        document.body.classList.remove('dark-mode');
        document.body.classList.add('light-mode');
        localStorage.setItem('dark-mode-settings', 'light');
    }
});

//チェックボックス切り替え判定
btn.addEventListener("change", () => {
	if (btn.checked === true) {
		document.body.classList.remove('light-mode');
		document.body.classList.add('dark-mode');
		localStorage.setItem('dark-mode-settings', 'dark');
	}else {
		document.body.classList.remove('dark-mode');
		document.body.classList.add('light-mode');
		localStorage.setItem('dark-mode-settings', 'light');
	}
});

//ローカルストレージ判定
if(localStorage.getItem('dark-mode-settings')==='dark') {
	document.body.classList.add('dark-mode');
	btn.checked = true;
}else if (localStorage.getItem('dark-mode-settings')==='light') {
	document.body.classList.add('light-mode');
}

CSSでダークモードを判定してますが、JavaScriptでもダークモードを判定しています。
両方で判定させる理由としては「OS設定 → ユーザー設定」の順で、モードの優先順位を指定したいからです。


メディアクエリだけの判定だと、チェックボックスの指定が優先されてしまい、OS設定でモードを変更してもWebサイトに反映されません。

逆にJavaScriptの判定を削除してメディアクエリだけの判定に指定した場合は問題なく作動はします。
しかし、ブラウザをリロードした際に、JavaScriptの読み込みが遅れることから、既存のCSSが先に読み込まれ、背景色にチラつきが見られます。

上記の理由からモードの判定はCSSJavaScriptの両方を指定する必要があります。

参考にした記事はこちら

あなたにおすすめの記事