- ブラウザの基本機能から JavaScript メディアクエリまで、ダークモード実装の範囲を段階的に広げていく 8段階の区分を整理
- 最も単純な方法は
<meta name="color-scheme" content="light dark"> または color-scheme: light dark の宣言だけで、ユーザーのカラースキーム設定に従わせる構成
- より高い段階では
light-dark() 関数、@media (prefers-color-scheme: dark)、スキーム別の 分離スタイルシートにより、色だけでなく画像や影まで幅広く調整可能
- ユーザーのシステム設定に従うだけでなく、Automatic・light・dark の3つの選択肢を提供するスイッチャーも構成でき、
:has() と実際の meta 要素を基準にテーマ判定が可能
- Safari の アクセシビリティ上の限界や、印刷時の
prefers-color-scheme の挙動観察まで含まれ、最近の CSS 機能だけでもライト・ダークモードの内蔵が容易になったことが分かる
ダークモードの段階別実装
-
Level 1: Barebone
- CSS を1行も書かなくても light/dark の区別を有効化でき、文書の head に
<meta name="color-scheme" content="light dark"> を追加するだけで、ブラウザがユーザーの カラースキーム設定に従い始める
content 属性の項目順には理論上意味があり、カラースキーム設定を指定していないユーザーには、空白区切りリストの最初の値が適用される
- 現在の OS 設定にはカラースキームを選ばないオプションがないため、実際には OS 設定と一致するスキームに落ち着く
content に単一の値だけを指定することもでき、その場合はユーザー設定を考慮せず、そのスキームを強制適用する
- このメタタグは、ある程度次の段階の CSS 方式に対応する HTML 側の手法として機能する
-
Level 2: Basic
- CSS では
html { color-scheme: light dark; } の宣言で ライト/ダークモードの区別を適用できる
- すでに DOM にメタタグがあるならこの宣言は不要で、HTML を制御できるなら、ブラウザが CSS を解析する前から指示を把握できるメタタグの使用が推奨される
- どちらの方式でも、ユーザーエージェントのデフォルトスタイルと、そこに含まれる ライト/ダークモードを活用できる
- ここに CSS を追加しつつ、CSS system colors の使用を中心に制限すれば、かなり整ったデザインを実現できる
- メタタグが常に文書全体に適用されるのに対し、CSS の
color-scheme 宣言はルート要素以外にも設定でき、この違いにより追加の活用余地がある
-
Level 3: Benign
- 比較的最近追加された CSS の
light-dark() 色関数で、シンプルなライト/ダークモード調整が可能
- 例では
background-color: light-dark(black, white); と color: light-dark(white, black); のように使い、第1引数はライトモード、第2引数はダークモードに適用される
- 引数には実際の色を直接入れることも、色として解釈される custom properties を入れることもできる
- この文書全体で、執筆時点ではこの段階だけが ブラウザ対応として十分ではない
-
Level 4: Bold
- 伝統的な
@media (prefers-color-scheme: dark) メディアクエリでダークモード切り替えを実装できる
light と dark のどちらを問い合わせる場合でも、単純な色変更に限られない 最大限のカスタマイズが可能
- ダークモードで画像をフィルタにより低彩度化したり、ボックスシャドウをアウトラインに置き換えたりするような調整もすべて可能
-
Level 5: Bisectional
- メディアクエリは HTML でも使え、
link 要素の media 属性に入れて スキーム別スタイルシートを分離できる
- 例として
light.css と dark.css をそれぞれ prefers-color-scheme: light と prefers-color-scheme: dark に結び付ける方式を提示
- カスタマイズ範囲が大きい場合は専用ファイル構成が適しており、ブラウザはクエリに一致しない CSS ファイルを無視できるため、ダウンロード対象が1つ減る可能性がある
-
Level 6: Ballistic
- JavaScript では
window.matchMedia('(prefers-color-scheme:dark)') で カラースキームのメディアクエリを利用できる
- 他のメディアクエリと同じ方式でライトまたはダークスキームかどうかを問い合わせ、その結果をもとに必要な処理を行える
- 実際の実装では、前段階の手法を1つだけに固執せず 組み合わせて適用できる
ユーザースイッチャーと高度なパターン
-
Level 7: Beyond
- ユーザーのシステム設定だけに依存せず、color scheme switcher を構築できる
- このスイッチャーは単純な真偽値ではなく、初期デフォルトとして
prefers-color-scheme に従う Automatic モードが必要
- その上にスイッチャーを載せれば、ユーザーは Automatic、light、dark の 3つのモードから1つを選べる
-
Level 8: Beguiling
- Level 7 のスイッチャー実装では通常、HTML 要素に
.dark クラスや data-theme="dark" のような属性を追加する方法が一般的
- その代わりに
:has() を使って、実際の <meta name="color-scheme" content="dark"> の存在を直接問い合わせられる
- 例では
html:has(meta[name="color-scheme"][content="dark"]) セレクタの下で、--color-bg、--color-text のような CSS 変数をダークモード用の値に設定している
- 別途クラスやデータ属性がなくても、実際の meta 要素を基準にテーマ判定が可能
追加の議論と観察
-
CSS Naked Day の観察
- スタイルを外して巡回したほぼすべてのサイトで ダークモード不在が目立ち、これがダークモードの段階分類につながった
- 新しいサイトをゼロから構築して新しいスタイルを書くなら、最近の CSS 機能によって ライト/ダークモードの内蔵が非常に簡単になったという言及を含む
-
Safari のアクセシビリティ問題
- 比較的最近まで Safari はダークモードで アクセシブルなリンク色を提供していなかったという指摘を含む
- 以前の CSS Naked Day ではこの問題を見つけ、メタタグを削除してライトカラースキームだけを使った経験に言及
- その後あらためてメタタグを追加したものの、旧バージョンの Safari ユーザーには アクセシビリティ低下が生じうることを認識
- Safari のダークモードではテキストボックスに 見える境界線がないことも確認されている
- ユーザーエージェントスタイルだけでは、正しいセマンティック HTML を使っていても完全なアクセシビリティは保証できず、今後の CSS Naked Day でも十分なスタイルを維持する方法を検討している
-
印刷と screen and 条件
- Bisectional の例で
screen and ... を使った理由として、プリンター対象の除外を意図したと言及
- テーマ非依存のコアスタイルシートや専用の印刷スタイルシートが別にあると仮定し、プリンターでダークモードがインクを多く使う可能性があるため、安全に分離しようという判断を示す
- 実際のテストでは、システムのダークモードを有効にした状態で印刷しても黒いテキストと白い紙だけが出力され、ブラウザは印刷にそのダークモードスタイルを適用していないようだと観察
- 追加テストでは印刷プレビューで
prefers-color-scheme は常に light と報告され、Firefox と Chromium で確認された
- 黒い紙と白インクを使うプリンターがあったら残念だ、という冗談めいた言及も含む
1件のコメント
Hacker Newsのコメント
userContent.cssでbackground-colorを指定するやり方が悪くないと思う