BLOG

CSS変数とlight-dark()関数を組み合わせて、シンプルかつ効率的にダークモード対応しよう

Written by uchida

INDEX

説明

近年のWebデザインでダークモードが重視される理由は、見た目のかっこよさだけではなく、ユーザー体験(UX)や技術的配慮にも深く関係しています。今回は、Webサイトのダークモード対応を、CSS変数とlight-dark()関数を使って効率よく行う記述を紹介します。

ダークモード対応の必要性

まず初めに、ダークモード対応の必要性・メリットを紹介します。

ユーザーの目の疲労を軽減

暗い環境(夜間や室内)では、白背景よりも暗い画面の方が目に優しいため、明暗差が少なくなり、長時間見ていても疲れにくいといったメリットがあります。

デバイスバッテリー消費を抑えられる

有機ELを用いたディスプレイでは、画面が黒に近いほど発光が少なく、省電力でサイト閲覧を行えます。

アクセシビリティの向上

明るい画面が苦手な視覚過敏ユーザーなどにも配慮でき、ユニバーサルデザインにも効果的です。

light-dark() 関数について

light-dark() は、CSSでダークモード・ライトモードのスタイルを簡潔に書き分けるための関数です。
CSSでカラーのスタイルを適用する際、下記のように1番目の引数にライトモード、2番目にダークモードを設定します。ルート要素にcolor-schemeプロパティを指定することで、ブラウザがテーマを認識できるようになり、使用ブラウザのモード切り替えに応じてライトテーマ用とダークテーマ用の値が出力されます。

:root { 
 color-scheme: light dark;
}
 
p { 
 color: light-dark(<ライトテーマ用の値>, <ダークテーマ用の値>); 
}

完成版

今回は、ダークモードへの切り替え方法で一般的な、トグルボタンUIを用いたモード切り替えを行いたいと思います。

実装手順

手順1(HTML / ページの枠組作成)

まずはマークアップから準備します。
今回は、buttonタグを使って、サイト全体のモード切り替えを行います。
HTMLでは、htmlタグに対して、あらかじめdata-theme属性を付与しておきます。

<!-- data-theme属性を付与 -->	
<html data-theme="light">
 <body>
   <main class="p-mode-change">
    <p class="p-mode-change__above">Now, you are using<strong class="p-mode-change__lead">Light Mode</strong></p>
     <div class="p-mode-change__below">
       <p class="p-mode-change__text">If your eyes are tired, <br />you should use <span class="">dark mode.</span></p>
       <button id="toggleButton" type="button" class="p-mode-change__toggle"></button>
     </div>
   </main>
 </body>
</html>

手順2(CSS / スタイル調整・カラーの変数宣言)

デフォルトのテーマカラーと、ダークモード用のテーマカラーの変数を定義しておきます。
変数でまとめておくことで、サイト全体の色変更も一括で効率よく行うことができます。

デザインによって、同じ色でも微妙な濃淡の違いがあるため、背景色で使うカラーには、--bg-color、文字色で使う場合には--text-colorなどを指定しております。
ダークモードでもライトモードでも色が変わらないパーツがあるかと思いますが、私の場合は混在しないように、 --unique-〇〇:と命名しています。(いずれもプロジェクトや個人で管理しやすいような命名が好ましいです。)

:root {
 // ブラウザへテーマ認識を伝える
 color-scheme: light dark;
 // light-dark()は、引数に応じて、lightモードとdarkモードで異なる値を返す
 --bg-color: light-dark(#fff, #111);
 --text-color: light-dark(#111, #fff);
 --line-color: light-dark(#333, #ccc);
 --gray-main: light-dark(#666, #999);
 // モード切り替えの対象外の色についてはユニークな変数名を命名
 --unique-white: #fff;
 --unique-gray: #ddd;
 --unique-green: #4ade80;
}

[data-theme="light"] {
 --bg-color: #fff;
 --text-color: #111;
 --line-color: #333;
 --gray-main: #666;
}


[data-theme="dark"] {
 // darkモードの時に上書きする変数
 --bg-color: #111;
 --text-color: #fff;
 --line-color: #ccc;
 --gray-main: #999;
}

// コンテンツ用スタイル記載
.....

ボタンは、一般的なトグルボタンのデザインにしていますが、こちらのサイトがジェネレーターを公開してくださっており、簡単にUIを再現することができました。

手順3(JavaScript / clickイベントでトグル処理を実装)

クリックイベントで data-theme を切り替え、モードに応じた表示とクラス付けを行います。

また、localstorageに選択中のテーマを保存する処理を記述しているので、ページ再読み込み時にもテーマが適用されます。

const toggleButton = document.getElementById('toggleButton')
const mainText = document.querySelector('.p-mode-change__lead')
const subText = document.querySelector('.p-mode-change__text')

// テーマの状態管理
const themeStore = {
 DARK: 'dark',
 LIGHT: 'light',

 get theme() {
  const theme = localStorage.getItem('theme')
  return theme === this.DARK ? this.DARK : this.LIGHT
 },

 set theme(value) {
  localStorage.setItem('theme', value)
  document.documentElement.setAttribute('data-theme', value)
 },
}

// テーマの更新
function updateTheme(theme) {
 themeStore.theme = theme
 const isDark = theme === themeStore.DARK
 toggleButton.classList.toggle('p-mode-change__toggle--is-on', isDark)
 toggleButton.setAttribute('aria-pressed', isDark)
 if (isDark) {
  mainText.innerHTML = 'Dark Mode'
  subText.innerHTML = 'If you prefer brighter contents, <br>you should use <span>light mode.</span>'
 } else {
  mainText.innerHTML = 'Light Mode'
  subText.innerHTML = 'If your eyes are tired, <br>you should use <span>dark mode.</span>'
 }
}

// 初期テーマの適用
updateTheme(themeStore.theme)

// トグルボタンのクリックイベント
toggleButton.addEventListener('click', function () {
 const currentTheme = themeStore.theme
 const newTheme = currentTheme === themeStore.DARK ? themeStore.LIGHT : themeStore.DARK
 updateTheme(newTheme)
})

CSS変数を使えば、一括で色を変更できたり、一部カラーの変更依頼があったとしても、柔軟に対応することができます。 また、微妙な濃さの違いの色が複数色ある場合なども柔軟に対応することができますので、light-dark()関数とも比較しながら、CSS変数を使ったやり方もぜひ活用してみてください。

参考文献