ダークモードは、もはや「おまけ機能」ではありません。AppleもGoogleも標準サポートし、ユーザーの約8割がダークモードを好むというデータもあります。
本記事では、CSS変数(カスタムプロパティ)と prefers-color-scheme を使った、実践的なダークモード実装を解説します。
ステップ1:CSS変数でカラーを管理する
ダークモード実装の鍵は「色をハードコーディングしない」こと。すべての色をCSS変数として :root に定義しておけば、後からダークモードの色に切り替えるだけで済みます。
| 変数名 | ライト | ダーク |
|---|---|---|
| --color-bg | #FFFFFF | #1A1A2E |
| --color-text | #1A1A1A | #E0E0E0 |
| --color-card | #F9F6F2 | #0F3460 |
| --color-border | #EAEAEA | #333333 |
<table class="var-table">
<tr><th>変数名</th><th>ライト</th><th>ダーク</th></tr>
<tr><td>--color-bg</td><td><span class="swatch" style="background:#fff"></span>#FFFFFF</td><td><span class="swatch" style="background:#1a1a2e"></span>#1A1A2E</td></tr>
<tr><td>--color-text</td><td><span class="swatch" style="background:#1a1a1a"></span>#1A1A1A</td><td><span class="swatch" style="background:#e0e0e0"></span>#E0E0E0</td></tr>
<tr><td>--color-card</td><td><span class="swatch" style="background:#f9f6f2"></span>#F9F6F2</td><td><span class="swatch" style="background:#0f3460"></span>#0F3460</td></tr>
<tr><td>--color-border</td><td><span class="swatch" style="background:#eaeaea"></span>#EAEAEA</td><td><span class="swatch" style="background:#333"></span>#333333</td></tr>
</table>
/* ===== ベースのレイアウト(デザインに合わせて調整してください) ===== */
.var-table {
/* 本体のスタイル */
}
.swatch {
/* 本体のスタイル */
}
/* ===== 動作のアニメーション ===== */
/* ライトモード(デフォルト) */
:root {
--color-bg: #FFFFFF;
--color-text: #1A1A1A;
--color-card: #F9F6F2;
--color-border: #EAEAEA;
}
/* ダークモード */
[data-theme="dark"] {
--color-bg: #1A1A2E;
--color-text: #E0E0E0;
--color-card: #0F3460;
--color-border: #333333;
}
ステップ2:OS設定を自動検知する
prefers-color-scheme メディアクエリを使えば、ユーザーのOS設定(ダークモード / ライトモード)を自動検知できます。
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #1A1A2E;
--color-text: #E0E0E0;
--color-card: #0F3460;
--color-border: #333333;
}
}
[data-theme="dark"] 方式と組み合わせるのがベストプラクティスです。
ステップ3:トグルスイッチを実装する
ユーザーが手動でライト / ダークを切り替えられるトグルスイッチ。下のデモを切り替えてみてください。
記事タイトル
ダークモードとライトモードをワンクリックで切り替えられます。CSS変数を入れ替えるだけの簡単実装です。
カードコンポーネント
<div class="mode-toggle" onclick="toggleDarkDemo()">
<span>☀️</span>
<div class="mode-toggle__track" id="mode-track">
<div class="mode-toggle__knob"></div>
</div>
<span>🌙</span>
</div>
<div class="preview" id="demo-preview">
<div class="preview__header">
<span class="preview__logo">Demo Site</span>
</div>
<div class="preview__body">
<h3 class="preview__title">記事タイトル</h3>
<p class="preview__text">ダークモードとライトモードをワンクリックで切り替えられます。CSS変数を入れ替えるだけの簡単実装です。</p>
<div class="preview__card">
<p class="preview__text" style="margin:0;">カードコンポーネント</p>
</div>
</div>
</div>
// テーマ切り替えトグル
const toggle = document.getElementById('theme-toggle');
toggle.addEventListener('click', () => {
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
document.documentElement.setAttribute('data-theme', isDark ? 'light' : 'dark');
// ユーザーの選択をlocalStorageに保存
localStorage.setItem('theme', isDark ? 'light' : 'dark');
});
// ページ読み込み時に保存されたテーマを復元
const saved = localStorage.getItem('theme');
if (saved) {
document.documentElement.setAttribute('data-theme', saved);
}
ステップ4:画像もダークモードに対応させる
テキストの色だけ変えても、明るい背景の画像が浮いてしまうと台無しです。filter プロパティで画像の明度を下げるか、ダークモード用の画像を用意しましょう。
/* ===== ベースのレイアウト(デザインに合わせて調整してください) ===== */
.mode-toggle__track {
/* 本体のスタイル */
}
.mode-toggle {
/* 本体のスタイル */
}
.preview__title {
/* 本体のスタイル */
}
.preview__logo {
/* 本体のスタイル */
}
.preview__body {
/* 本体のスタイル */
}
.preview {
/* 本体のスタイル */
}
.preview__header {
/* 本体のスタイル */
}
.mode-toggle__knob {
/* 本体のスタイル */
}
.preview__card {
/* 本体のスタイル */
}
.preview__text {
/* 本体のスタイル */
}
/* ===== 動作のアニメーション ===== */
/* 方法1:filterで明度を下げる */
[data-theme="dark"] img {
filter: brightness(0.85);
}
/* 方法2:picture要素で画像を出し分け */
/* HTML側 */
/* <picture>
<source srcset="logo-dark.png"
media="(prefers-color-scheme: dark)">
<img src="logo-light.png" alt="Logo">
</picture> */
まとめ:ダークモードは「色の設計」から
効果的なダークモード実装のポイントをまとめます。
- CSS変数で色を一元管理 → 切り替えは変数の上書きだけ
- OS設定を自動検知 →
prefers-color-scheme - 手動切り替え →
data-theme属性 + localStorage - 画像の対応 → filter or picture要素
最も重要なのは「最初からCSS変数で設計する」こと。後からダークモードを追加するのは大変ですが、最初から変数化しておけば、変数を上書きするだけで完成します。