This site is an archive of ama.ne.jp.

color-schemeとprefers-color-schemeのつかいかた

概要

  • metaタグまたはスタイルシートで color-scheme を設定することで、ブラウザにカラーテーマを指定することができる。
  • メディア特性の prefers-color-scheme を用いることで、ユーザがどのようなカラーテーマを要求しているかを取得できる。
  • あまねけ!では prefers-color-scheme を用いてカラーテーマを自動で切り替え、従前より提供していた手動での切り替え機能も引き続き使用できるようにした。

color-theme によるカラーテーマの指定

スタイルシートでの指定

CSSプロパティの color-scheme を設定すると、ブラウザにカラーテーマを指定することができる。color-scheme には以下の属性を設定できる。

  • normal 1
  • light
  • dark

light および dark はスペース区切りで2つ以上並べることができ、この場合は先に指定したカラーテーマを推奨していることを示せる。

:root {
  color-scheme: dark light;
}

カラーテーマを指定することで、自前でスタイルシートを用意することなくスクロールバーやフォーム要素を含むページの色合いを切り替えることができる。ただし、 color-scheme はFirefox2およびInternet Explorerには対応していない。そのため、Firefoxが対応するまでは暗いカラーテーマのスタイルシートを用意しておく必要があるかもしれない。

color-scheme全ての要素に適用可能とされている。しかし、body要素以下に color-scheme: dark を適用しつつ、ルート要素( :root または html )には color-scheme: dark を指定しなかった場合は、文字色や背景色が変わらないなどの致命的な不具合がみられた3

metaタグでの指定

color-schememetaタグでも設定でき、ルート要素に対して color-scheme プロパティを設定するのと同じ効果を持つ。

<meta name="color-scheme" content="dark light">

prefers-color-scheme による優先カラーテーマの取得

メディア特性の prefers-color-scheme を用いることで、ユーザーがどのようなカラーテーマを優先的に要求しているかを取得できる。 prefers-color-scheme は以下の値を持ちうる。

  • light
  • dark

prefers-color-scheme をメディアクエリで用いることにより、ユーザの要求に合わせてスタイルを切り替えることができる。例えば、以下のようなスタイルシートはユーザの優先カラーテーマに合わせて背景色を切り替える。

/* 暗いカラーテーマ */
@media screen and (prefers-color-scheme: dark) {
  body {
    background-color: black;
  }
}

/* 明るいカラーテーマ */
@media screen and (prefers-color-scheme: light) {
  body {
    background-color: white;
  }
}

prefers-color-scheme は多くのブラウザで対応しているものの、残念ながらInternet Explorerには対応していない4。上記のように全てのカラーテーマを prefers-color-scheme メディアクエリに閉じ込めてしまうと、未対応のブラウザではいずれのスタイルも適用できないため、必要に応じてどちらかのテーマにフォールバックさせてもよいかもしれない。

/* 明るいカラーテーマ(またはデフォルト) */
@media screen {
  body {
    background-color: white;
  }
}

/* 暗いカラーテーマ */
@media screen and (prefers-color-scheme: dark) {
  body {
    background-color: black;
  }
}

あまねけ!での対応

あまねけ!では、これまでページ上部に toggle color scheme ボタン(切り替えボタン)を設置して、ブラウザのデフォルトカラーテーマ1とオリジナルの暗いカラーテーマを切り替えられるようにしていた。

color-scheme の採用

まず、オリジナルの暗いカラーテーマを廃止し、 color-scheme を用いてカラーテーマを切り替えることを検討したが、以下の理由で不採用とした。そのため、スクロールバーの色は従来通り明るいままとなっている5

  • metaタグでの color-scheme の指定は、読み込み後に手動で切り替えることができない。
  • CSSプロパティでの color-scheme の指定は、疑似クラス :has() がなければ手動で切り替えることができない。
  • 一部のブラウザでは color-scheme でのカラーテーマの切り替えに対応していない。

ただし、ここでいう「手動で切り替える」とはスタイルシートのみを用いて切り替えることを指しており、JavaScriptでのプロパティの書き換えなどは含まない。

prefers-color-scheme の採用

次に、 prefers-color-scheme を用いて初期表示時のカラーテーマを自動で切り替えることを検討した。

prefers-color-scheme に合わせて初期表示時のカラーテーマを設定した場合、切り替えボタンを用いた以下のような切り替えパターンが考えられる。

  • 明るいカラーテーマで表示する場合
    • (A) prefers-color-scheme に未対応で切り替えボタンを偶数回クリックした
    • (B) prefers-color-scheme: light で切り替えボタンを偶数回クリックした
    • (C) prefers-color-scheme: dark で切り替えボタンを奇数回クリックした
  • 暗いカラーテーマで表示する場合
    • (D) prefers-color-scheme に未対応で切り替えボタンを奇数回クリックした
    • (E) prefers-color-scheme: light で切り替えボタンを奇数回クリックした
    • (F) prefers-color-scheme: dark で切り替えボタンを偶数回クリックした

これまでの実装と影響範囲を考慮し、最終的には以下のような実装を行った。

@media screen and (prefers-color-scheme: light) {
  /* (E) 奇数回クリックした際の挙動(暗いカラーテーマ) */
}
@media screen and (prefers-color-scheme: dark) {
  /* (F) 偶数回クリックした際の挙動(暗いカラーテーマ) */
}

prefers-color-scheme に未対応のブラウザへの対処

切り替えのロジック上、全てのパターンを網羅するには prefers-color-scheme に未対応のブラウザと prefers-color-scheme: dark であるブラウザを区別する必要がある。しかし、 prefers-color-scheme に未対応のブラウザでは prefers-color-scheme を含むメディアクエリを一切使用できず、 prefers-color-scheme に未対応かどうかを明示的には検出できない。

この問題は、明るいカラーテーマをブラウザに頼らず明示的に設定することで解決できる。具体的には、フォールバックのスタイルには偶数回で明るく、奇数回で暗く切り替えるように設定し、 prefers-color-scheme: dark のスタイルでそれらを逆に上書きすればよい。

@media screen {
  /* (A,B) 偶数回クリックした際の挙動(明るいカラーテーマ) */
  /* (D,E) 奇数回クリックした際の挙動(暗いカラーテーマ) */
}
@media screen and (prefers-color-scheme: dark) {
  /* (C) 奇数回クリックした際の挙動(明るいカラーテーマ) */
  /* (F) 偶数回クリックした際の挙動(暗いカラーテーマ) */
}

しかし、明るいカラーテーマを指定する手間と古いブラウザに対応するメリットを比較して、今回は prefers-color-scheme に未対応のブラウザには対処しないことにした。今後、これらの環境では切り替えボタン自体が表示されない。もし切り替えボタンが使えなくなって困っていたら、すぐに対処するのでコメントなどで知らせてほしい。

強制ダークモードへの対処

また、サイトの color-scheme 指定にかかわらずブラウザのデフォルトカラーテーマを暗いものに切り替える機能、いわゆる強制ダークモードを適用している場合は、切り替えボタンをクリックしても2つの暗いカラーテーマ(ブラウザのデフォルトとサイトのオリジナル)しか使用できない。これについても、オリジナルの明るいカラーテーマを指定すれば解決できる。とはいえ、強制ダークモードを適用したいユーザが明るいカラーテーマを希望することは少ないと考えられるため、こちらも特に対処しない。

おまけ: チェックボックスでスタイルを切り替える

チェックボックスの状態を区別する :checked 擬似クラスセレクタ一般兄弟結合子 ~を用いることで、CSSの機能だけでチェックボックスの状態に応じてスタイルを切り替えられる。現在、あまねけ!ではこの手法でカラーテーマを切り替えている。

この手法の欠点は、チェックボックスより階層が上の要素にはスタイルを当てられないということである。現状主要なブラウザで使用できる範囲では、JavaScriptを用いて親を辿らなければならない。「ある状態のチェックボックスを子に持つようなbody要素」のようなセレクタには、疑似クラス :has() の実装が必要である。

<html>
  <head>
    <title>チェックボックスでスタイルを切り替える</title>
    <style>
    #main {
        background-color: red;
    }
    input[type="checkbox"]#toggle:checked ~ #main {
        color: #eee;
        background-color: blue;
    }
    </style>
  </head>
  <body>
    <input id="toggle" type="checkbox">
    <section id="main">
      <div>チェックボックスでスタイルを切り替える</div>
    </section>
  </body>
</html>

ブラウザで表示

参考


  1. 多くのブラウザでは明るいカラーテーマとなる。 

  2. 現時点での最新バージョンはFirefox 86.0である。 

  3. Google Chrome 88.0で確認した。 

  4. MDNの prefers-color-schemeではFirefox Androidも未対応になっているが、手元のFirefox Daylight 86.1.1では動作している。 

  5. ただし、 color-scheme の指定とは関係なく、スクロールバーの色がbody要素の背景色に追従するブラウザ(Firefoxなど)もある。