2025.6.16 技術面のTipsを追記しました。
以前から作ろう作ろうと思っていた、ダークモードの切り替え機能を実装しました!:)
ヘッダーの切り替えボタンから、サイト全体の背景色を変更できます。夜間の読書などにお役立てください🌙
同じブラウザで閲覧すれば、設定した背景色が引き継がれます。初期設定はOS上の設定を参照しているので、iPhoneやPCなどのシステム設定をダークモードにしている方は、何もしなくても暗い背景色になっている…はず。これまでと同様の色で閲覧したい方は、ヘッダーのボタンから切り替えることで元に戻せます。
以下は技術的な話。(2025.6.16 全体的に追記しました)
今回のダークモード実装ではJavaScriptのLocalStorageを利用しています。
実装の参考にした記事はこちら。感謝です!
サイトをリニューアルした際、ダークモード用の色は設計していなかったので、CSSを書き直しながら2年前の自分を正座させたい気持ちになりましたね…笑。
ダークモード切り替え処理に加えて、サイト内の色情報もCSS変数で参照するように変更しています。最初からそう書いとけば良かったよォ〜〜
ダークモード実装までの流れ
上記の参考記事を読んでいただくのが一番わかりやすいですが、当サイトにおけるダークモード実装までの流れも以下に残します。
CSSとJavaScriptの知識がなんとなくあり、個人サイト作るのが好きな方、ご参考までに。
※前提
WordPress、またはHTMLファイル中心の個人サイトを所持している方向けです。
Astro.jsやNext.jsなどのフレームワークを利用している方は、ダークモード実装用のプラグインやオプションが用意されている可能性が高いため、そちらをまずチェックしてみてください。
※当サイトはEleventyによる静的サイト実装なので、専用プラグインは多分…無い!(調べてない)
1. CSS内のカラーコードをCSS変数に統一する
ダークモード実装に向けた下準備です。最初からCSS変数を取り入れていればこの作業は不要だった…! ※MDNによるCSS変数の解説はこちら 。
2年前の自分が何も考えていなかったので、当サイト内の色指定はCSSに直接カラーコードを記述していました。正確にはSCSS変数を利用してたんですが、まあコンパイル後はこんな感じ。
body {
color: #181614;
background-color: #fefbf9;
}
.btn--color {
background-color: rgba(55, 128, 122, 0.7);
}
rgba記述で透明化処理してた箇所も多々。SCSS変数だと background-color: rgba($color: $keyColor, $alpha: 0.7);
みたいにザクザク書けるからつい…。
このままだとダークモード対応できないので、CSS全体の色指定を書き直します。rgba記述にも対応させるため、カラーコードとrgb数値の双方をCSS変数として定義。
※実際はもっと細々と定義してますが、一部抜粋
:root {
--bgColor: #fefbf9;
--bgColorRgb: 254, 251, 249;
--textColor: #181614;
--textColorRgb: 24, 22, 20;
--keyColor: #37807a;
--keyColorRgb: 55, 128, 122;
}
body {
background-color: var(--bgColor);
color: var(--textColor);
}
.btn--color {
background-color: rgba(var(--keyColorRgb), 0.7);
}
サイト内の色情報をある程度は設計していたのが功を奏し、一括置換でなんとかなる範囲で良かったです。SCSS変数使ってなかったり、無秩序に色増やしまくってたら挫折してたかもしれない。。
2. ダークモード用のCSS変数を書く
ここからが本番。
ダークモード閲覧が有効化された場合に参照するCSS変数を書きます。ユーザーの端末設定のみを参照する形なら、JavaScriptの記述は不要です。以下でOK。
@media (prefers-color-scheme: dark) {
:root {
--textColor: #fefbf9;
--textColorRgb: 254, 251, 249;
--bgColor: #333939;
--bgColorRgb: 51, 57, 57;
--keyColor: #37807a;
--keyColorRgb: 55, 128, 122;
}
}
背景色は真っ黒にすると目に痛いため、森の林床をイメージしたダークグレーに調整。
最初はもうすこしブラウンがかったグレーも検討したんですが、最終的には、ロゴにも使っているキーカラーのグリーンを元にした色に落ち着きました。
もちろんこれだけだと何かしらの色が破綻するので、ダークモード時のみ有効な調整用CSSもあれこれ書きます。ロゴもSVGコードにして文字色をCSS制御可能にしたり。
rgba系の記述がいちばんめんどくさかったな………(通常時とダークモードで同一のalpha値だと見づらい箇所が多々あったため、ほぼ全部微調整した)
3. ダークモード切り替え用のスイッチを実装する
ここまでで完成にしても良かったんですが、サイト上からダークモード切り替えできた方がやっぱり親切かな〜ということで、もうひとがんばり。
切り替えスイッチの選択情報は、JavaScriptのLocalStrageで保持します。
まずはサイト全ページのheadタグ内に以下コードをインラインで追加。
<script async>
"use strict";
(function () {
const prefers = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
const fromStorage = localStorage.getItem("kokyushobo-color-mode");
const colorMode = (fromStorage === "system" || fromStorage == null) ? prefers : fromStorage === "light" ? "light" : "dark";
window.document.documentElement.dataset.colorMode = colorMode;
})();
</script>
上記コードの目的は以下。
- LocalStorageのダークモード情報を参照
- LocalStorageに保持情報がなければ、ユーザー端末のダークモード情報を参照
- 参照した情報に沿って、html要素のdata属性を更新する
こちらの記述が無いと、ダークモード情報参照に掛かるタイムラグにより、ページ遷移時にちらつきが発生します。こちらを真っ先に実行することで、htmlタグに閲覧モードの情報を付与して、こう。
<html lang="ja" data-color-mode="light">
システムのダークモード有効時には data-color-mode="dark"
になっていたらOK。
続けてLocalStorage更新用の関数を書きます。切り替えスイッチが押されたら、
- htmlタグに付与されている、現在の閲覧モードを表すdata属性を参照
- 参照した情報とは異なるモードに切り替え、data属性を更新する
- 新たな閲覧モードの情報をLocalStorageに保存する
大まかな流れはそんな感じ。
function viewModeManager() {
const viewModeBtn = document.querySelector('#modeChangeBtn');
if (viewModeBtn) {
viewModeBtn.addEventListener('click', () => {
let currentMode = window.document.documentElement.dataset.colorMode;
if (currentMode === 'dark') {
window.document.documentElement.dataset.colorMode = 'light';
localStorage.setItem('kokyushobo-color-mode', 'light');
}
else {
window.document.documentElement.dataset.colorMode = 'dark';
localStorage.setItem('kokyushobo-color-mode', 'dark');
}
});
}
}
最後に、先ほど書いたCSSを調整。
システムのダークモード情報を参照する @media (prefers-color-scheme: dark)
ではなく、html要素に付与されたdata属性に基づいてCSS変数を変更するように書き換えます。
[data-color-mode="dark"] {
--textColor: #fefbf9;
--textColorRgb: 254, 251, 249;
--bgColor: #333939;
--bgColorRgb: 51, 57, 57;
--keyColor: #37807a;
--keyColorRgb: 55, 128, 122;
}
これにて完成!おおよそ二日くらいの作業でした👏
ほんとはtransitionと組み合わせて、モード切り替え時にサイト全体の色がふわーっと変化するようにしたかったのですが、body要素に後からtransitionを足すと、既存のheaderとかで使ってる背景色transitionに干渉してしまったため、そこは今回見送りました。
やっぱり後から付け足すと多少の技術的負債は残りますね。
次はブログのカテゴリ機能とページネーション周りをなんとかしたいところ。
あとはLocalStorageを使って、小説ページのフォント切り替え機能も実装したいです。