WebサイトにJavaScriptでダークモード切り替えるボタンを実装する
JavaScript でダークモードを実装したい
ダークモードに切り替えるボタンを作成しようと思い、記事や動画などをあさりましたが、理想とする実装方法が見つかりませんでした。
根気よくあさっていたら良さそうな記事を見つけました。
海外の Abbey Perini さんが紹介している実装方法がめちゃくちゃ参考になりました。
以下の項目に該当する人におすすめです。
- ユーザーの OS のテーマを判定して、その内容をもとにサイトのテーマを適応したい人
- CSS の変数(カスタムプロパティ)を使ってテーマを管理したい人
- React や Vue でも使いたい人
- JQuery を使わず実装したい人
実行したい処理
👇 は実装するダークモードのイメージです。
if(/* 初回アクセスの場合 */) {
// ユーザーのOSテーマを元にサイトのテーマを適応
} else {
// セッションストレージの情報を元にテーマを適応
}
ライトモードとダークモードの CSS をかく
ライトモードとダークモードように CSS のクラスを用意します。ここでは、is-theme-light
とis-theme-dark
としておきます。
メンテナンスしやすいようにカラーは変数で管理します。
:root,
.is-theme-light {
--base-color: white;
--primary-color: skyblue;
--secondary-color: mistyrose;
--font-color: black;
}
.is-theme-dark {
--base-color: black;
--primary-color: lightskyblue;
--secondary-color: lavenderblush;
--font-color: whitesmoke;
}
body {
color: var(--font-color);
background var(--base-color);
}
テーマを適応する
<html>
タグに CSS のクラスを追加する処理を書きます。<html>
タグは、documentElement
を使用してを表現します。
次に、セッションストレージにテーマを保存する機能を作成します。sessionStorage
のsetItem()
メソッドを使います。setItem()
第一引数の key を、第二引数は key に渡す値を渡します。key の名前はtheme
としておきます。
これらをまとめて一つの関数にします。
const applyTheme = (themeName) => {
sessionStorage.setItem('theme', themeName);
document.documentElement.className = themeName;
};
applyTheme()
に渡された引数(クラス名)が、<html>
タグのクラスに追加され、sessionStorage
の keytheme
の値に渡されるようになります。
初回セッションかどうかを判定する
sessionStorage
に keystatus
を作成して、滞在時に key 値を渡す処理を書きます。
初期値に空文字を設定しておきます。
const applyVisited = (status) => {
status = '';
sessionStorage.setItem('status', status);
};
ユーザーの OS テーマを元にサイトのテーマを適応する
これは、初回アクセス時に実行する処理です。
matchMedia()
メソッドを使ってユーザーの OS テーマを判別する処理を書いていきます。matchMedia()
の引数に(prefers-color-scheme: dark)
を渡す事で、ユーザーの OS テーマがダークモードであるかどうかを判別できます。
const prefersColorSchemeDark = matchMedia(
'(prefers-color-scheme: dark)'
).matches;
条件分岐と先ほど作った関数applyTheme()
を使って、初回アクセス時に実行する処理を書きます。OS テーマがダークモードの場合はis-theme-dark
を、そうでない場合はis-theme-light
をapplyTheme()
の引数に渡します。
const initialTheme = () => {
const prefersColorSchemeDark = matchMedia(
'(prefers-color-scheme: dark)'
).matches;
if (prefersColorSchemeDark) {
applyTheme('is-theme-dark');
} else {
applyTheme('is-theme-light');
}
};
セッションストレージからテーマの情報を取得する
これは、初回アクセス以外、ページ遷移や再読み込みが発生した時に実行します。getItem()
メソッドを使ってセッションストレージに keytheme
に保存されている情報を取得します。
const storageTheme = sessionStorage.getItem('theme');
条件分岐とapplyTheme()
を使って適応するテーマの処理をおこないます。
export const getStorageTheme = () => {
const storageTheme = sessionStorage.getItem('theme');
if (storageTheme === 'is-theme-dark') {
applyTheme('is-theme-dark');
} else if (storageTheme === 'is-theme-light') {
applyTheme('is-theme-light');
}
};
状況に応じてテーマを適応する
準備が整いましたので、冒頭で述べた 👇 の処理を書いていきます。
if(/* 初回アクセスの場合 */) {
// ユーザーのOSテーマを元にサイトのテーマを適応
} else {
// セッションストレージの情報を元にテーマを適応
}
実際にかく処理は少々異なります。
if(/* 初回アクセスじゃない場合 */) {
// 初回アクセス以外、ページ遷移や再読み込みが発生した時に実行する処
// セッションストレージの情報を元にテーマを適応
} else {
// 初回アクセス時に実行する処理
// ユーザーのOSテーマを元にサイトのテーマを適応
}
まとめると 👇 のようになります。
const discriminationTheme = () => {
const getStrageVisited = sessionStorage.getItem('status');
if (getStrageVisited) {
getStorageTheme();
} else {
initialTheme();
applyVisited('visted');
}
};
セッションストレージの keystatus
の情報を取得して、情報があればgetStorageTheme()
を実行、そうでなければ、initialTheme()
とapplyVisited()
を実行します。applyVisited()
には引数としてvisited
を渡します。
ボタンクリックでテーマを切り替える
最後にボタンをクリックした時にテーマを切り替える処理を書いていきます。
const switchTheme = () => {
const storageTheme = sessionStorage.getItem('theme');
if (storageTheme !== 'is-theme-dark') {
applyTheme('is-theme-dark');
} else {
applyTheme('is-theme-light');
}
};
全ての処理をまとめると 👇 のようになります。
const applyVisited = (status) => {
status = "";
sessionStorage.setItem("status", status);
};
const applyTheme = (themeName) => {
sessionStorage.setItem("theme", themeName);
document.documentElement.className = themeName;
};
const initialTheme = () => {
const prefersColorSchemeDark = matchMedia(
"(prefers-color-scheme: dark)"
).matches;
if (prefersColorSchemeDark) {
applyTheme("is-theme-dark");
} else {
applyTheme("is-theme-light");
}
};
const getStorageTheme = () => {
const storageTheme = sessionStorage.getItem("theme");
if (storageTheme === "is-theme-dark") {
applyTheme("is-theme-dark");
} else if (storageTheme === "is-theme-light") {
applyTheme("is-theme-light");
}
};
const switchTheme = () => {
const storageTheme = sessionStorage.getItem("theme");
if (storageTheme !== "is-theme-dark") {
applyTheme("is-theme-dark");
} else {
applyTheme("is-theme-light");
}
};
const discriminationTheme = () => {
const getStrageVisited = sessionStorage.getItem("status");
if (getStrageVisited) {
getStorageTheme();
} else {
initialTheme();
applyVisited("visted");
}
};
theme.js として保存して、HTML ファイルに読み込みましょう。
<button>
タグのonclick
属性にswitchTheme()
を渡せば、テーマ切り替えボタンの完成です。
<script src="theme.js"></script>
<button onclick="switchTheme()"></button>
React で使うには
React で使うには、switchTheme
とdiscriminationTheme
をexport
して、switchTheme
はonClick
属性に、discriminationTheme
は App.js などのファイル内のuseEffect
の中に記述していただければ OK です!
ただ、React ではuseState
に置き換えらそうなコードがいくつかあるので、今度 React バージョンも公開できればと思います。
Discussion