つくる ダークモード切替
このレッスンで分かること
classList.toggleは、付いていれば外し、付いていなければ付けますtoggleの戻り値は「実行後に付いているか」の真偽値で、そのまま表示の切り替えに使えます- 見た目の切り替えは CSS に任せ、JavaScript は class の付け外しだけを担当します
つくる ダークモード切替 とは
クリックイベントと classList を組み合わせて、ページの配色を明暗で切り替える機能です。
ここまでで手に入れたもの
第8章では、要素を取ってくる querySelector、文字を書き換える textContent、class を付け外しする classList を学びました。この章に入ってからは、addEventListener で処理を出来事に結び付け、event オブジェクトからどれが押されたかを読み取り、入力欄の値を扱えるようになりました。
ここまでの部品を組み合わせると、もう「押したら見た目が変わる」がつくれます。今回はダークモードの切り替えボタンです。押すたびに配色が反転し、もう一度押すと元に戻ります。
要点は、JavaScript が色を直接いじらないことです。style.backgroundColor に色を代入していく書き方でも動きますが、色の数だけ行が増え、どこで何色にしたのか追えなくなります。かわりに、JavaScript は body に dark という class を付けたり外したりするだけにします。その class が付いたときの配色は CSS 側にすでに書いてあります。
body.dark {
background-color: #1b1f27;
color: #e8eaee;
}役割を分けておくと、あとから配色を変えたくなっても CSS だけを直せば済みます。JavaScript は一切さわりません。この分け方は、ダークモードにかぎらず「開いている」「選ばれている」「読み込み中」といった状態の表現すべてに使えます。
classList の 4 つのメソッド
第8章で出てきた classList をおさらいします。
| メソッド | 動き | 戻り値 |
|---|---|---|
| add | 付ける。すでにあれば何もしない | なし |
| remove | 外す。無ければ何もしない | なし |
| toggle | あれば外し、無ければ付ける | 実行後に付いているか |
| contains | 付いているかを調べる | true か false |
切り替えボタンは、add と remove を自分で振り分けても書けます。
if (document.body.classList.contains("dark")) {
document.body.classList.remove("dark");
} else {
document.body.classList.add("dark");
}間違ってはいませんが、これとまったく同じことを 1 行で書けるのが toggle です。
document.body.classList.toggle("dark");条件分岐が消えるぶん、読み違いも起きません。切り替えを書くときは toggle を第一候補にしてください。
toggleは実行後の状態を真偽値で返します。付いた直後ならtrue、外れた直後ならfalseです。この戻り値をそのまま使うと、ボタンの文言もいっしょに切り替えられます。もう一度containsで調べ直す必要はありません。
body を取る
body は特別な要素で、document.body と書けばいつでも取れます。document.querySelector("body") でも同じものが返りますが、document.body のほうが短く、意図もはっきりします。
const themeToggle = document.querySelector("#theme-toggle");
themeToggle.addEventListener("click", function () {
const isDark = document.body.classList.toggle("dark");
themeToggle.textContent = isDark ? "ライトモード" : "ダークモード";
});第3章で学んだ三項演算子が、ここで短く効いています。isDark が true なら次に押すとライトに戻るので、ボタンには行き先である ライトモード を出します。ボタンの文言を「いまの状態」にするか「押したらどうなるか」にするかは設計の分かれ目ですが、行き先を書くほうが押す前に迷いません。
なぜ body に付けるのか
class を付ける相手は、変えたい範囲のいちばん外側にします。ページ全体の配色を変えるなら body です。CSS の子孫セレクタを使えば、body.dark .section のように中の要素までまとめて指定できます。
body.dark .section {
background-color: #242a34;
border-color: #333a46;
}もし .section それぞれに class を付けて回ると、要素の数だけ処理が増え、あとから追加した要素には付きません。外側 1 か所に付けて中は CSS で受ける、という形にしておくと、JavaScript は 1 行のままで済みます。
状態を class で表す、という型
今回覚えてほしいのは、ダークモードの作り方そのものよりも、その裏にある型です。画面の状態は class の名前で表し、その名前が付いたときの見た目は CSS に書く。JavaScript は名前を付け外しするだけ。この 3 行が守られていれば、機能が増えても JavaScript は太りません。
現場でよく見る class 名を挙げると次のようになります。
| class 名 | 表している状態 |
|---|---|
| is-open | メニューやパネルが開いている |
| is-active | いま選ばれている項目 |
| is-loading | 読み込み中で操作させたくない |
| has-error | 入力に問題がある |
is- や has- を先頭に付けるのは、見た目のための class と区別するためです。.card は形を決める class、.is-active は状態を表す class、と読み分けられます。次の回では has-error を実際に使います。
もう一点、切り替えたことをブラウザに伝えたいなら aria-pressed などの属性もいっしょに変えます。読み上げソフトを使う人に、いま押されている状態かどうかが伝わります。今回は必須にしませんが、覚えておくと役に立ちます。
今回書くこと
ヘッダーの中に、id="theme-toggle" のボタンを足します。class="theme-toggle" と type="button" も付けてください。見た目の CSS は用意してあります。
JavaScript では、そのボタンに click を登録し、document.body.classList.toggle("dark") を呼びます。戻り値を受け取って、ボタンの文字も ライトモード と ダークモード で切り替えます。
動きを確かめるときは、必ず 2 回押してください。1 回押して暗くなっても、もう一度押して明るく戻らなければ切り替えになっていません。往復して初めて完成です。
よくある間違い
add だけ書いている
themeToggle.addEventListener("click", function () {
document.body.classList.add("dark");
});1 回目は暗くなりますが、2 回目以降は何も起きません。add はすでに付いていれば黙って何もしないからです。toggle に置き換えます。
class 名にドットを付けてしまう
document.body.classList.toggle(".dark");classList に渡すのは class 名そのものです。ドットが要るのは querySelector のセレクタのときだけです。.dark という名前の class が付いてしまい、CSS には当たりません。
className を上書きしてしまう
document.body.className = "dark";これは class 全体を dark だけで置き換える書き方です。元から付いていた class があれば消えてしまいます。付け外しには classList を使います。
課題
- HTML の
.site-headerの中、navのうしろにid="theme-toggle"class="theme-toggle"type="button"のボタンを足し、文字は「ダークモード」にする - JavaScript で
#theme-toggleにclickを登録する - 処理の中で
document.body.classList.toggle("dark")を呼ぶ toggleの戻り値を使って、ボタンの文字を「ライトモード」と「ダークモード」で切り替える