カラーモードを切り替えるスイッチを実装する方法

以前にCSSだけでダークモードに対応させる方法を投稿しました。これはこれで簡単にダークモードに対応できて良かったんですが、私のように、OSの設定はダークモードでもWebサイトはライトモードで閲覧したいと思われる方が少なからずいらっしゃるのではないかと考え、そうするとやはりカラーモードの切り替えができるスイッチを実装したいなと思った次第です。
CSSだけでダークモードに対応する方法
会社や個人、ブログやポートフォリオなどのWebサイトをCSSだけでダークモードに対応する方法をご紹介します。サイトを閲覧しているユーザーが、ダークモードとライトモードを自由に切り替えることのできるボタンを実装しているサイ […]

https://neatdesignjournal.com/dark-mode-css-only/

上記の記事にも追記はしていますが、今回はその中身についてより詳しい解説をしたいと思います。
全体の構成
カラーモード対応をどのように行いたいかによって実装方法は変わると思うんですが、当サイトでは以下のような内容でダークモード対応を行っています。
- サイトの初期表示は、ユーザー環境(OSの設定)に従って表示される。
- その後は、再アクセス時やページ遷移時にカラーモードが元に戻らないように、ユーザーが選択したカラーモード情報をローカルに保存しておき、それに合わせて表示させる。
ということでまずは完成版をご覧ください。
See the Pen color-mode-switch by ryskyshd (@ryskyshd) on CodePen.
HTML
では早速中身に入っていきたいと思います。最初はカラーモードを切り替えるスイッチのHTMLから。
<button type="button" class="color_mode_switch" aria-label="カラーモードを切り替え"></button>
極力無駄な要素は省いて必要最低限のコードにするのが私のこだわりなので、切り替えスイッチ部分はbutton
要素でマークアップしました。他にはinput type="checkbox"
とlabel
要素を使う方法もありますが、これだと必要な要素が2つになるため採用していません。
aria-label
はアクセシビリティに対応した属性で、装飾目的などの空要素はaria-label
を付与してこの要素が一体何を表しているのかを明示します。
aria-label - ARIA | MDN
aria-label 属性は対話型要素にラベル付けする文字列値を定義します。
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label

CSS
続いてはCSSですが、まずはスイッチ部分について解説します。
button {
all: unset;
cursor: pointer;
&:focus-visible {
--outline-color: #0077e6;
outline: 2px solid var(--outline-color);
outline-offset: 2px;
}
}
最初に、button要素のデフォルトスタイルをall: unset;
で削除します。これでUAスタイルシートで指定されたデフォルトスタイルはほぼ全てリセットされます。そして、cursor: pointer;
でマウスオーバー時の挙動を指定します。
次の&:focus-visible
以降では、キーボード操作時にスイッチ自体にフォーカスが当たった時のスタイルを指定しています。all: unset;
で全てのスタイルをリセットしたので、このままだとキーボード操作時にフォーカスが当たらなくなるため、アクセシビリティ的にダメな状態です。フォーカス時にoutline
を設けて要素自体から2px離して表示するようにしています。
.color_mode_switch {
--switch-block-size: 1.5rem;
--switch-inline-size: calc(var(--switch-block-size) * 2);
--switch-radius: calc(infinity * 1px);
--switch-color-light: #d99c00;
--switch-color-dark: #3f6fd1;
--switch-transition: var(--transition-color-mode);
position: relative;
inline-size: var(--switch-inline-size);
block-size: var(--switch-block-size);
background-color: var(--switch-color-light);
border-radius: var(--switch-radius);
transition: background-color var(--switch-transition);
&::before {
--thumb-size: var(--switch-block-size);
--thumb-color: #fff;
--thumb-border-size: 2px;
position: absolute;
inset: 0;
display: inline-grid;
place-content: center;
inline-size: var(--thumb-size);
block-size: var(--thumb-size);
content: "\e518";
color: var(--switch-color-light);
font-family: "Material Icons Round";
background-color: var(--thumb-color);
border: var(--thumb-border-size) solid var(--switch-color-light);
border-radius: var(--switch-radius);
box-sizing: border-box;
transition:
inset-inline-start var(--switch-transition),
border-color var(--switch-transition);
}
&.active {
background-color: var(--switch-color-dark);
&::before {
inset-inline-start: calc(100% - var(--thumb-size));
content: "\e51c";
color: var(--switch-color-dark);
border: var(--thumb-border-thickness) solid var(--switch-color-dark);
}
}
}
続いてはスイッチ自体のスタイルです。カスタムプロパティをこれでもかというくらい使っているので見にくい面もあるかと思いますが、よく見るとそんなに難しいことはしていません。
カスタムプロパティ部分
--switch-block-size: 2rem;
--switch-inline-size: calc(var(--switch-block-size) * 1.8);
--switch-radius: calc(infinity * 1px);
--switch-color-light: #d99c00;
--switch-color-dark: #3f6fd1;
--switch-transition: var(--transition-color-mode);
スイッチ自体の高さは2rem
としていますが、これはお好みで変えてください。1rem
でも1rlh
でもいいですし32px
でも何でも大丈夫です。また、スイッチの横幅はスイッチの高さの1.8倍としました。これもお好みで変えていただいて結構です。サイトのデザインに合うようにお好きに改変してください。
次のcalc(infinity * 1px)
は錠剤型のデザインにするための呪文です。あまり深い意味は考えなくても綺麗な錠剤型になるのでまぁよしとしましょう。9999pxとか999emでもいいみたいですけどね。
次の2つはスイッチの色ですね。light
の時に黄色系、dark
の時に青系の色を指定しています。ライトモード時は太陽、ダークモード時は夜をイメージした色にすると見た目的に分かりやすくなります。この辺もお好みで…(以下省略)
最後はtransition
ですから、スイッチの中の丸ぽっちがスライドする時のスピードとかを指定しています。var(--transition-color-mode)
としているのは、後にも出てきますがスイッチを切り替えた時に背景や文字色が変化するスピードとスイッチの丸ぽっちがスライドするスピードを一緒にするためのものです。ちなみに中身は0.25s ease
となっています。これもお好みで…(以下略)
スイッチの外側部分
position: relative;
display: block;
inline-size: var(--switch-inline-size);
block-size: var(--switch-block-size);
background-color: var(--switch-color-light);
border-radius: var(--switch-radius);
transition: background-color var(--switch-transition);
スイッチの外側部分とは、スイッチの中の丸ぽっち以外の部分と捉えていただいたら良いかと思います。丸ぽっち部分のスタイルにカスタムプロパティで定義した値をそれぞれ指定していきます。
丸ぽっち部分
&::before {
--thumb-size: var(--switch-block-size);
--thumb-color: #fff;
--thumb-border-size: 2px;
position: absolute;
inset: 0;
display: inline-grid;
place-content: center;
inline-size: var(--thumb-size);
block-size: var(--thumb-size);
content: "\e518";
color: var(--switch-color-light);
font-family: "Material Icons Round";
background-color: var(--thumb-color);
border: var(--thumb-border-size) solid var(--switch-color-light);
border-radius: var(--switch-radius);
box-sizing: border-box;
transition:
inset-inline-start var(--switch-transition),
border-color var(--switch-transition);
}
丸ぽっち部分はAppleやGoogleではサム(thumb)と言われているそうなので、カスタムプロパティもそれで定義してみました。なお、サム部分はbutton
要素の擬似要素(::before
)で作成します。
縦横のサイズを指定してposition: absolute;
、inset: 0;
でそれいっぱいに広がるようにしています。その他の指定は適宜いい感じの見た目になるように微調整している感じですね。この辺もお好みで…
とはいえ、なかなか一から作成するのは面倒かと思いますので、そんな時に便利なサイトをご紹介します。
トグルボタンHTML&CSSデザインジェネレーター【コピペ可】
トグルボタンのコードを自動生成します。JavaScript不使用のチェックボックス形式、またはJavaScriptを使うbutton形式で実装可能です。
https://webspe.net/tools/toggle-button/

細かくカスタマイズできますし、HTML、CSS、Javascript、jQueryのコードを自動で出力してくれますので、ある程度のものがこのサイトだけで完成します。便利ですね。ありがとうございます。
あとは見た目的により分かりやすくするためにGoogle Iconsを表示させてます。
スイッチ押下後のスタイル
&.active {
background-color: var(--switch-color-dark);
&::before {
inset-inline-start: calc(100% - var(--thumb-size));
content: "\e51c";
color: var(--switch-color-dark);
border: var(--thumb-border-thickness) solid var(--switch-color-dark);
}
}
jQueryでスイッチを押下したら.active
というクラスを付与するようにして、それに対してスタイルを当てます。背景色を変化させ、丸ポッチ部分を反対側へスライド、アイコンを変える、ボーダカラーもこれに合わせて変化させます。
サイト全体のCSS
:root {
--color-dark: #000;
--color-light: #fff;
--transition-color-mode: 0.25s ease;
}
html {
transition: color var(--transition-color-mode), background-color var(--transition-color-mode);
&[data-color-mode="light"] {
color: var(--color-dark);
background-color: var(--color-light);
}
&[data-color-mode="dark"] {
color: var(--color-light);
background-color: var(--color-dark);
}
}
CSSの最後はサイト全体部分です。ここの指定でダークモード時、ライトモード時のスタイルを個別に指定することができます。
次に出てくるjQueryで、スイッチの切り替えごとにhtml
要素にdata-color-mode="dark"
またはdata-color-mode="light"
を付与または切り替えるようにして、CSSでは[data-color-mode="dark"]
以下にダークモード時のスタイル、[data-color-mode="light"]
以下にライトモード時のスタイルを指定します。
これでCSSは完成です。
jQuery
$(function () {
const $html = $("html");
const savedTheme = localStorage.getItem("color-mode");
if (savedTheme) {
$html.attr("data-color-mode", savedTheme);
if (savedTheme === "dark") $(".color_mode_switch").addClass("active");
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
$html.attr("data-color-mode", "dark");
$(".color_mode_switch").addClass("active");
} else {
$html.attr("data-color-mode", "light");
}
$(".color_mode_switch").on("click", function () {
$(this).toggleClass("active");
const newMode = $(this).hasClass("active") ? "dark" : "light";
$html.attr("data-color-mode", newMode);
localStorage.setItem("color-mode", newMode);
});
});
ここまで偉そうに語ってきましたが、jQueryだけはあまり詳しくないのでChatGPT先生と会話しながら自分の実装したい形になるようにコードを作成していただきました。便利ですね。
先ほどもお話ししたように、スイッチのオンオフに伴ってhtml
要素にdeta-*
属性の付与を行うのと、ユーザーの選択したカラーモードをローカルに保存するなどをjQueryで実装しています。
最後に
いかがでしたでしょうか。これでカラーモードの切り替えができるスイッチの実装とカラーモード対応ができたかと思います。最後にもう一度完成品を載せておきますので、コードを色々と弄ってみてください。
See the Pen color-mode-switch by ryskyshd (@ryskyshd) on CodePen.
参考サイト
CSS変数とlight-dark()関数を組み合わせて、シンプルかつ効率的にダークモード対応しよう
近年のWebデザインでダークモードが重視される理由は、見た目のかっこよさだけではなく、ユーザー体験(UX)や技術的配慮にも深く関係しています。今回は、Webサイトのダークモード対応を、CSS変数を使って効率よく行う記述を紹介します。
https://evoworx.dev/blog/dark_mode/

トグルボタンHTML&CSSデザインジェネレーター【コピペ可】
トグルボタンのコードを自動生成します。JavaScript不使用のチェックボックス形式、またはJavaScriptを使うbutton形式で実装可能です。
https://webspe.net/tools/toggle-button/
