js-cookieでウェブサイトのダークモード表示設定をユーザーごとに保存しておく方法

少し前にブログをリニューアルして、そのときに一緒にダークモードの対応を行いました。
ただ、人によっては「システム環境設定に依存しないで、常にダークモードの方がいい!」人や「逆にライトモードの方が見やすい!」という人もいると思い、個別に設定できるように変更してみました。
今後デザインは変えていく予定ですが、メニュー右上の「表示設定」をクリックすると設定モーダルが表示されます。

このラジオボタンを選択すると、それぞれのモードに固定されます。
- ライト
- ダーク
- ナイト
- システム設定に合わせる(デフォルト)
ちなみに「ライトモード」と「ダークモード」以外に「ナイトモード」という表示も追加していて、これは深夜暗い部屋でも見やすいように、色を全体的に暗くして画像の輝度も下がります。
今回はこれの実装方法についてまとめておきます。
ダークモード自体の実装方法は有名ですが、それを保存する方法についてはあまり見かけなかったので、ぜひ参考にしてください。
ダークモードの対応
そもそもまずはダークモードの対応が必要です。
CSS変数を利用して、ライトモード(通常)時と@media (prefers-color-scheme: dark) {}を使って、ダークモード時の色を設定します。
:root{
--c-primary: #0076b5;
--c-secondary: #17C2C7;
--c-background-base: #F7F9FB;
--c-background-primary: #FFF;
--c-background-secondary: #F0F2F5;
--c-text-base: #555;
--c-text-lighter: #676767;
--c-text-link: #0076b5;
}
@media (prefers-color-scheme: dark) {
:root{
--c-primary: #EBCB1A;
--c-secondary: #FF178D;
--c-background-base: #2B2B2B;
--c-background-primary: #313131;
--c-background-secondary: #242424;
--c-text-base: #EAEAEA;
--c-text-lighter: #B7B7B7;
--c-text-link: #0076b5;
}
}これでライトモードとダークモードの指定はできましたが、このままだとメディアクエリでのみの設定になるので、bodyに特定classが付いたときにも変数が変わるようにしておきます。
body.dark-mode{
--c-primary: #0076b5;
--c-secondary: #17C2C7;
--c-background-base: #F7F9FB;
--c-background-primary: #FFF;
--c-background-secondary: #F0F2F5;
--c-text-base: #555;
--c-text-lighter: #676767;
--c-text-link: #0076b5;
}js-cookieの導入
js-cookieを使うと、JavaScriptでCookieの登録や取得が簡単にできます。こちらから読み込みます。
js-cookieでCookieの登録
Cookieを登録したい場合はCookies.set('Cookie名', 値);で登録できます。
Cookies.set('darkmode', darkModeVal);Cookieを取得したい場合はCookies.get('Cookie名');で取得できます。
Cookies.get('darkmode');あとはラジオボタンでどこがチェックされているのかを判定するのと、判定に応じてbodyにclassを追加するだけです。
let getDarkModeVal = function () {
let radios = document.getElementsByName('darkmode');
for (let i = 0; i < radios.length; i++) {
if (radios[i].checked) {
return radios[i].id;
}
}
}
let setDarkModeVal = () => {
let darkModeVal = getDarkModeVal();
switch (darkModeVal) {
case 'light':
document.body.classList.add("light-theme");
document.body.classList.remove("dark-theme");
document.body.classList.remove("night-theme");
break;
case 'dark':
document.body.classList.remove("light-theme");
document.body.classList.add("dark-theme");
document.body.classList.remove("night-theme");
break;
case 'night':
document.body.classList.remove("light-theme");
document.body.classList.remove("dark-theme");
document.body.classList.add("night-theme");
break;
default:
document.body.classList.remove("light-theme");
document.body.classList.remove("dark-theme");
document.body.classList.remove("night-theme");
break;
}
Cookies.set('darkmode', darkModeVal);
}
const darkMode = Cookies.get('darkmode');
if (darkMode) {
document.getElementById(darkMode).checked = true;
} else {
document.getElementById('system').checked = true;
}
// チェックした時の挙動
let radios = document.getElementsByName('darkmode');
for (let i = 0; i < radios.length; i++) {
radios[i].addEventListener('change', () => {
setDarkModeVal();
});
}PHPでCookieに合わせてclassを追加する
いまのままだと、ページが表示された後にJavaScriptが読み込まれてclassが付くまでの間はライトモードが表示されてしまいます。
一瞬ライトモードが表示されて、そのあとダークモードになったりするのはむしろ目がチカチカしてしまうので、Cookieが設定されてある場合はPHPで最初からclassを付けておくようにしましょう。
PHPでやることはCookieの取得のみで、isset( $_COOKIE['Cookie名'] )で取得ができるので、取得したあとは条件分岐でclassの中身を設定します。
<?php if ( isset( $_COOKIE['darkmode'] )){
if($_COOKIE['darkmode'] == 'light'){
$darkModeClass = 'light-theme';
}elseif($_COOKIE['darkmode'] == 'dark'){
$darkModeClass = 'dark-theme';
}elseif($_COOKIE['darkmode'] == 'night'){
$darkModeClass = 'night-theme';
}
}?>
<body class="<?php echo $darkModeClass ?>">これで、ダークモードのCookieが設定されてある場合は最初からダークモードのclassが付いた状態で表示されます。



PubSubHubbubを利用してWebサイトの更新をリアルタイムに通知しよう
Visual Studio Codeで英単語のスペルチェックをしてくれる拡張機能「Code Spell Checker」
pointer-eventsプロパティでクリックイベントを無効化にする|気になるCSSプロパティ
JavaScriptのforEach内で「continue」や「break」のような動作をさせる方法
Visual Studio CodeでCSVの編集を見やすく行う拡張機能「Edit csv」
Google Maps APIをローカル開発環境で使用するときの制限設定方法
Visual Studio Codeで簡易的なローカルサーバーを起動して、コード保存時に自動でブラウザをリロードする拡張機能「Live Server」
Visual Studio CodeからFTPソフトのTransmitを使用する拡張機能「Transmit」
コーディング時に「アノテーションコメント」を使ってコードを見やすく管理する
Nuxt.jsで「Classic mode for store/ is deprecated and will be removed in Nuxt 3.」のエラーメッセージが表示される場合の対処法
iTerm2で「Use System Window Restoration Setting」を設定しているとアラートが表示されて機能しない
Google Chromeのサイト内検索(カスタム検索)機能を別のプロファイルに移行する方法
iPadで入力モードを切り替えずに数字や記号をすばやく入力する方法
iPhoneやiPadでYouTubeの再生速度を3倍速や4倍速にする方法
Keynoteで有効にしているはずのフォントが表示されない現象
MacのKeynoteにハイライトされた状態でコードを貼り付ける方法
AirPodsで片耳を外しても再生が止まらないようにする方法
iTerm2でマウスやトラックパッドの操作を設定できる環境設定の「Pointer」タブ
DeepLで「インターネット接続に問題があります」と表示されて翻訳できないときに確認すること
Ulyssesの「第2のエディタ」表示を使って2つのシートを横並びに表示する
Figma × Keyboard Maestroでどこまで効率化できる?
マウス操作の完成度が高いウインドウリサイズアプリ「Magnet」
Macで複数ディスプレイを使っている場合に便利な設定集
AppCleanerでMacアプリを関連ファイルごと完全に削除する
操作に没頭できる!Firefox版 Arcのようなブラウザ「Zen Browser」
chezmoi(シェモア)で始めるdotfiles管理
GitHubの通知を見逃さない!通知に特化したアプリ「Gitify」
Keyboard Maestroの変数基礎
Neovimを使い始める最初の一歩として便利な「LazyVim」
ウェブサイトをmacOSアプリとしてラッピングする「Unite Pro」