JOURNAL

スマホの『ダークモード』自動切り替えの仕組み(prefers-color-scheme)

スマホの設定でダークモードにしてるのに、開いたサイトだけ眩しい白背景のまま、というのに地味にイラッとした経験ありませんか。自分はよくあります。CSSのprefers-color-schemeを使えば、OSの設定に合わせて配色を自動で切り替えられるので、今回はその基本を軽くまとめておきます。

書き方自体はこれだけ

/* 通常(ライトモード)の配色 */
body {
  background: #fff;
  color: #111;
}

/* OSがダークモードのときだけ適用 */
@media (prefers-color-scheme: dark) {
  body {
    background: #111;
    color: #eee;
  }
}

この仕組みの良いところは、サイト側で何もしなくても、利用者が普段使ってる端末の設定に勝手に追従してくれる点です。切り替えボタンを押させる手間もなく、OS全体の見た目とサイトの見た目が自然に揃う。

実装した瞬間、「なんだこんな数行で済むのか」と若干拍子抜けしました。

ただ、OS設定に完全に任せきりにするのではなく、サイト側にも独自の切り替えボタンを用意しておくのはおすすめです。「OSはダークモードだけど、このサイトだけは明るく見たい」みたいな人が一定数いるので(自分もそういうことがあります)、両方用意しておくのが現実的なバランスかなと思っています。

ボタンを作るならJS側でも状態を拾う

独自の切り替えボタンを作る場合、CSSの@mediaだけでは完結せず、JavaScript側でも今どちらのモードかを知る必要が出てきます。そこで使うのがwindow.matchMedia()です。

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

// OS側の設定がリアルタイムに変わったときも検知できる
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    console.log(e.matches ? 'ダークモードになった' : 'ライトモードになった');
  });

ユーザーが手動で切り替えた設定はlocalStorageに保存しておいて、次回訪問時にOS設定より優先して復元する、という組み合わせがよくある実装パターンです。