JavaScriptでダークモードやライトモードのテーマカラーを判別する



PCやスマートフォン、タブレット端末や各Webブラウザでは、ダークモードやライトモードなどのテーマカラーの設定があり、OSの設定に合わせて自動でブラウザのテーマカラーを設定していたり、手動でどちらかのテーマカラーに設定したりと環境は様々です。
Web制作では、必要に応じてこれらのテーマカラーに合わせてWebデザインを作っていく必要もできてきます。

テーマカラーでの配色を含むデザインの切り替えにおいては、CSSのみでもユーザーが利用している環境のテーマカラーを判別することはできますが、CSSの能力を超える、より動的な制御や外部との連携が必要な場合には、JavaScriptが必要になります。

例えば、Webサイトのロゴやコンテンツ画像など、単なる装飾ではなく「コンテンツ」としてタグで配置されている画像を、テーマに応じて切り替えたい場合や、ユーザーによる手動のテーマ切り替え機能を実装する場合、CSSのみでの判別では対応できないこともあります。
また、グラフ描画ライブラリ(Chart.js)や地図ライブラリ(Google Maps)など、外部ライブラリ使ってコンテンツを作成している場合は、ライブラリ独自のDOM構造でコンテンツを生成することが多いため、CSSでの配色の変更は難しく、JavaScriptのオプションで指定する必要があります。

ここでは、JavaScriptでダークモードとライトモードのテーマカラーによるスタイルの切り替えについて、サンプルコードを交えてご紹介します。

まずは簡単なHTML構造を用意しておきます。

HTML

<main>

  <div class="card">
    <h2>カードのタイトル 1</h2>
    <p>カード内のコンテンツです。</p>
    <p>表示モードに合わせて背景色や文字色が変わります。</p>
    <p><a href="#">サンプルリンク</a></p>
  </div>
  <div class="card">
    <h2>カードのタイトル 2</h2>
    <p>カード内のコンテンツです。</p>
    <p>表示モードに合わせて背景色や文字色が変わります。</p>
  </div>

</main>


この後にご紹介するサンプルでは、上記のHTML構造は共通のものとします。

ちなみに、CSSのみでテーマカラーを判別する場合は、下記のようにメディアクエリを使って、「prefers-color-scheme」のメディア特性に適用するスタイルを定義します。

CSS

:root {
  --text-color: #222;
  --background-color: #f8f9fa;
  --card-background: #ffffff;
  --link-color: #007bff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --text-color: #e9ecef;
    --background-color: #121212;
    --card-background: #1e1e1e;
    --link-color: #64b5f6;
  }
}

body {
  color: var(--text-color);
  background-color: var(--background-color);
  transition: all 0.3s;
  padding: 2rem;
}

main {
  max-width: 800px;
  margin: 0 auto;
}

a {
  color: var(--link-color);
}

.card {
  background-color: var(--card-background);
  padding: 1.5rem;
  border-radius: 8px;
  margin-bottom: 1.5rem;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}


メディアクエリでは、「prefers-color-scheme: dark」として、ダークモードの際にCSSの変数(カスタムプロパティ)で一元管理している配色をダークモード用に上書きし、それぞれの要素に適用している配色に反映させています。

(上:ライトモード 下:ダークモード)

CSSのみで実装したダークモード/ライトモードの判別によるスタイルの切り替え



Webブラウザによるダークモードとライトモードの切り替えの確認は、デベロッパーツールで手軽に切り替えて確認することができます。
デベロッパーツールは、Windowsは「Ctrl + Shift + I」または「F12」、Macは「Command + Option + I」のショートカットキーで手軽に起動できます。
「Elements」タブのスタイルの表示にて、色の設定アイコンから prefers-color-scheme を light または dark に設定して表示を切り替えます。

デベロッパーツールのレスポンシブモードによるダークモードとライトモードの切り替え



前述したとおり、CSSだけでは対応できない場合は、JavaScriptでテーマカラーを判別してスタイルを切り替える必要があります。

JavaScriptでテーマカラーを判別する


JavaScriptでテーマカラーを判別してCSSでスタイルを適用させる場合は、HTML要素にdata-theme属性やclass属性を付与して実装する方法が一般的です。

まずは、data-theme属性を付与する方法を見ていきます。

テーマカラーを判別してdata-theme属性を付与


CSSでは、:root でサイト全体で使うグローバルなCSS変数を定義し、ライトモードのスタイルに適用する配色を指定する中、属性セレクタ [data-theme=”dark-mode”] で「data-themeという属性の値がdark-modeである要素」にスタイルを適用させ、ダークモード用の配色に上書きします。

CSS

:root {
  --text-color: #222;
  --background-color: #f8f9fa;
  --card-background: #ffffff;
  --link-color: #007bff;
}

[data-theme="dark-mode"] {
  --text-color: #e9ecef;
  --background-color: #121212;
  --card-background: #1e1e1e;
  --link-color: #64b5f6;
}

body {
  color: var(--text-color);
  background-color: var(--background-color);
  transition: all 0.3s;
  padding: 2rem;
}

main {
  max-width: 800px;
  margin: 0 auto;
}

a {
  color: var(--link-color);
}

.card {
  background-color: var(--card-background);
  padding: 1.5rem;
  border-radius: 8px;
  margin-bottom: 1.5rem;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}


対象の要素のプロパティに指定しているCSS変数の値が上書きされ、ダークモード用の配色としてスタイルが適用されます。
transitionプロパティでは、0.3秒かけて滑らかに変化するようにしています。

JavaScriptでは、matchMediaメソッドを使うことで、テーマカラーの判別を行うことができます。
matchMediaメソッドは、指定されたメディアクエリ文字列のパース結果を、MediaQueryListオブジェクトとして返します。

以下、サンプルコードになります。

JavaScript

const mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');

const updateTheme = (event) => {
  const isDark = event.matches;
  document.documentElement.setAttribute('data-theme', isDark ? 'dark-mode' : 'light-mode');
};

updateTheme(mediaQueryList);

mediaQueryList.addEventListener('change', updateTheme);


「window.matchMedia(‘(prefers-color-scheme: dark)’)」のメディアクエリリストを取得では、ブラウザに「OSやブラウザの設定はダークモードですか?」と問い合わせて、その監視オブジェクトを変数 mediaQueryList に保存しています。
matchMediaメソッドが返した結果から、.matchesで true か false を変数 isDark に格納し、DOM操作で.setAttributeを使って、data-theme属性に dark-mode か light-mode かを設定します。
現在ダークモードであれば、matchesにtrue、そうでなければfalseが返ってきます。

現在ダークモードであれば、matchesにtrue、そうでなければfalseが返ってくる


テーマを更新する処理を実装するupdateTheme関数は、初期読み込み時に一度実行します。
そのあとユーザーが設定を変更する場合には、変更があった時に関数を実行するようにしています。

実装後、デベロッパーツールでは、html要素にdata-theme属性が付与され、dark-mode とテーマカラーが指定されているのが確認できます。
またCSSのスタイルも、data-theme属性に対するスタイルが適用されているのが確認できます。

JavaScriptによるテーマカラーの判別とdata-theme属性の付与

テーマカラーを判別してclass属性を付与


次に、class属性を付与する方法を見ていきます。
CSSは、上記のdata-theme属性の部分を、classセレクタの指定に変更するだけとなります。
classセレクタ「.dark-mode」にスタイルを適用させるようにして、ダークモード用の配色に上書きします。

CSS

:root {
  --text-color: #222;
  --background-color: #f8f9fa;
  --card-background: #ffffff;
  --link-color: #007bff;
}

body.dark-mode {
  --text-color: #e9ecef;
  --background-color: #121212;
  --card-background: #1e1e1e;
  --link-color: #64b5f6;
}

body {
  color: var(--text-color);
  background-color: var(--background-color);
  transition: all 0.3s;
  padding: 2rem;
}

main {
  max-width: 800px;
  margin: 0 auto;
}

a {
  color: var(--link-color);
}

.card {
  background-color: var(--card-background);
  padding: 1.5rem;
  border-radius: 8px;
  margin-bottom: 1.5rem;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}


ユーザーの環境がダークモードであれば、classセレクタ「.dark-mode」に指定しているCSS変数の値に上書きされ、ダークモード用の配色として、対象の要素にスタイルが適用されます。

JavaScriptも、上記のdata-theme属性の付与の場合と流れはほとんど変わらず、matchMediaメソッドを使ってテーマカラーを判別し、返ってきた結果をもとにclass属性に「dark-mode」または「light-mode」の値を設定します。

JavaScript

const mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');

const updateTheme = (event) => {
  const isDark = event.matches;
  document.body.setAttribute('class', isDark ? 'dark-mode' : 'light-mode');
};

updateTheme(mediaQueryList);

mediaQueryList.addEventListener('change', updateTheme);


DOM操作では「document.body.setAttribute()」として、body要素にclass属性を付与しています。

実装後、デベロッパーツールでは、body要素にclass属性が付与され、dark-mode とテーマカラーが指定されているのが確認できます。
またCSSのスタイルも、対象のclassに対するスタイルが適用されているのが確認できます。

JavaScriptによるテーマカラーの判別とclass属性の付与

まとめ


ダークモードとライトモードの判別からのスタイルの適用は、CSSのみでも可能ですが、Webサイトの作りによってはJavaScriptでの判別が必要になることもあります。

JavaScriptでは、matchMediaメソッドを使うことで、テーマカラーの判別を行うことができます。これにより、data-theme属性やclass属性を付与して、CSSでのスタイル調整が可能になります。

また、matchMediaメソッドについては、メディアクエリや表示領域のリサイズの判定、hover動作のデバイスの判別など、様々なことが可能です。
以下の記事で使い方をご紹介していますので、ぜひ参考にしてください。