ライトテーマとダークテーマの色をCSSで管理する方法
ライトテーマとダークテーマを用意するとき、CSSの各所に色を直接書いていると、背景だけ切り替わって文字やボタンの色が残ることがあります。背景・カード・文字・ボタンの色を役割ごとにまとめておけば、両方の画面を修正しやすくなります。ここではCSS変数と端末の表示設定を使い、2つのテーマの色を管理する方法を紹介します。
色を「役割」で分け、同じCSS変数名を使う
CSS変数(カスタムプロパティ)は、色などの値に名前を付け、複数の場所で再利用する仕組みです。たとえばページ背景を --bg、本文文字を --text、カードの面を --surface と名付けます。var(--bg) と書けば、背景色の実際の値を別の場所で管理できます。
ポイントは、ライトとダークで変数名を変えず、中に入る色だけを変えることです。ボタンも背景と文字を別々に管理します。明るい色を単純に暗く反転するのではなく、それぞれのテーマで文字と背景を組み合わせて考えます。
ライト・ダークの色を定義し、設定に合わせて切り替える
次はページ、カード、ボタンを対象にした最小限のCSS例です。:root に初期のライト用の色を置き、@media (prefers-color-scheme: dark) でダーク用の値を上書きします。prefers-color-scheme はOSやブラウザーの表示設定に応じた配色を判定するCSSの仕組みです。
:root {
color-scheme: light dark;
--bg: rgb(248 250 252);
--surface: rgb(255 255 255);
--text: rgb(30 41 59);
--button-bg: rgb(29 78 216);
--button-text: rgb(255 255 255);
}
@media (prefers-color-scheme: dark) {
:root {
--bg: rgb(15 23 42);
--surface: rgb(30 41 59);
--text: rgb(226 232 240);
--button-bg: rgb(147 197 253);
--button-text: rgb(15 23 42);
}
}
body { background-color: var(--bg); color: var(--text); }
.card { background-color: var(--surface); }
.button {
background-color: var(--button-bg);
color: var(--button-text);
}
コードの rgb() は赤・緑・青の数値で色を指定する方法です。同じ色を6桁の16進数で表すHEXコードでは、各変数は次の組み合わせになります。
| 色の役割 | ライト | ダーク |
|---|---|---|
ページ背景(--bg) |
#F8FAFC | #0F172A |
カード背景(--surface) |
#FFFFFF | #1E293B |
本文文字(--text) |
#1E293B | #E2E8F0 |
ボタン背景(--button-bg) |
#1D4ED8 | #93C5FD |
ボタン文字(--button-text) |
#FFFFFF | #0F172A |
このように要素側では変数名だけを使うため、色を変更する際はテーマ別の定義を調整するだけで、同じ役割の色に反映できます。color-scheme: light dark はフォーム部品やスクロールバーなど、ブラウザー標準の表示にも対応可能な配色を伝えます。ただし、それだけでサイト独自の背景や文字の色が自動設定されるわけではありません。
両テーマで文字・ボタン・切替の動作を確認する
色の確認はライトとダークを別々に行います。今回の例では、本文文字とページ背景のコントラスト比はライトで約13.98:1、ダークで約14.48:1です。ボタンの文字と背景はそれぞれ約6.70:1、約9.90:1となり、いずれもWCAG(Webコンテンツのアクセシビリティ基準)の通常サイズの文字に対するAA基準、4.5:1以上を満たします。これは表の不透明な単色同士で計算した結果であり、画像や透過色を重ねる場合は別途確認が必要です。
カード内の文字、リンク、フォーム、アイコン、ホバー時やキーボード操作時の表示も、両方のテーマで点検しましょう。prefers-color-scheme は端末などの設定に追従しますが、ページ内の切替ボタンで利用者が好みを選ぶ機能や、その選択を保存する機能までは提供しません。手動切替が必要なら、別途JavaScriptなどで選択状態を扱い、変数の上書き方法を設計します。