ドキュメントやマーケティングを 静的 HTML で配信しているチームは、今もライト用とダーク用のカラートークンを二重管理しがちです。@media (prefers-color-scheme: dark) のブロックを丸ごと複製し、さらに製品都合の手動トグル用に data-theme を増やす——この三重構造は、2026 年現在も「最初のペイントは正しいのに、数フレーム後にだけズレる」という古典的バグの温床です。light-dark() は、各トークンを「明るい値, 暗い値」の一宣言に折り畳みます。同時に color-scheme: light dark を :root(多くの場合は html)へ置くと、スクロールバーやフォームなど UA クロームがアクティブな配色と整合しやすくなります。本稿は React のテーマプロバイダ無しでビルドされる Eleventy・Astro・Hugo の出力を想定し、@supports での段階的フォールバック、コントラストと強制配色の検証、そして Safari / WebKit 実機サインオフがヘッドレスだけでは足りない理由を整理します。広色域ブランド色まで扱う場合は、知覚的に揃えたトークン設計として 静的 HTML での OKLCH と広色域 CSS と往復参照すると、ライト面とダーク面の両方で破綻しにくいです。
この記事では意思決定用のマトリクス、コピペ可能な CSS 断片、コントラストのチェックポイント、そしてレンタル Mac mini を使った Safari チェックリストまで持ち帰れるように構成しました。テーマ関連のイベントは、可能なら CSS バンドルのハッシュと一緒に計測基盤へ送り、宣言的パスへの移行が本当に進んだかをプロダクト側と合意形成しやすくしてください。
二重パレットがテーマ不具合を量産する理由
人手で維持するライト/ダーク変数は、時間とともに必ずドリフトします。デザイナが片方の --text だけ更新し、もう一方を忘れると、WCAG のコントラストは「夕方以降のセッション」で初めて赤くなる、という地獄が再発します。重複は CSS のバイトも膨らませ、2026 年初頭の公開マーケテンプレの観測では、テーマ周りだけで gzip 後 18~32 KB に達する例も珍しくありません。light-dark() は、その大半を「トークン一行」へ圧縮できます。
JavaScript で data-theme を切り替える方式は、手動トグルの自由度は高い一方、キャッシュ層と初回ペイントの競合、そしてサーバ側の初期 HTML とローカル保存値の不一致から FOUC を招きやすいです。静的サイトでは、宣言的な color-scheme と light-dark() に寄せた方が、移動部品が減ります。
テレメトリ上、エンタープライズ向けトラフィックのおよそ 5~8% は依然として light-dark() を解釈しないブラウザに乗っている前提で計画するのが現実的です。@supports not (color: light-dark(white, black)) の枝を用意し、そこで prefers-color-scheme に逃がしてください。
最後に、テーマ移行は「見た目」だけの話ではありません。計測イベントにバンドル識別子を載せると、レガシー JS トグルがまだ残っているワークスペースを特定しやすく、サポート問い合わせのラベ付けも安定します。
color-scheme とセットで light-dark() を書く
まず両方の配色を UA に広告し、そのうえでトークンを中央化します。
:root {
color-scheme: light dark;
--bg: light-dark(#ffffff, #0b0d12);
--fg: light-dark(#0b0d12, #f5f7fb);
--border: light-dark(#d7dbe4, #2a3140);
}
body {
background: var(--bg);
color: var(--fg);
}
セマンティック HTML と整合させるなら、html に color-scheme を置き、meta name="theme-color" やフォームの既定配色が同じ物語を語るようにします。
先端構文を包むフォールバックは次の形が読みやすいです。
@supports not (color: light-dark(white, black)) {
:root { --bg: #ffffff; --fg: #0b0d12; }
@media (prefers-color-scheme: dark) {
:root { --bg: #0b0d12; --fg: #f5f7fb; }
}
}
静的ジェネレータは、タイポグラフィトークンと同じチャンクへこれらの宣言を隣接させてください。遅延読み込みされた CSS チャンクへ分割すると、チャンク到着の一瞬だけ配色が古いまま残り、録画に映る「一フレーム事故」が増えます。
マトリクス:light-dark とメディアクエリ
| アプローチ | 強み | リスク |
|---|---|---|
light-dark() + color-scheme | トークンごとに単一の真実 | Safari のマイナー更新ごとにネイティブ UI を再確認する必要 |
prefers-color-scheme のみ | 互換範囲が広い | ルール重複とドリフト |
| JS の data-theme | 手動トグルの自由度 | FOUC とキャッシュ不整合 |
ネイティブ入力、表、コードブロック
チェックボックス、レンジ、日付入力は color-scheme から UA スタイルを引きます。フォーカスリングが --bg の両面で 3:1 を満たすか、ライト/ダークの実機で必ず確認してください。シンタックスハイライト付きの pre は、ライト前提の背景色を直書きしがちです。ダーク専用パネルなら、そのコンポーネントだけ color-scheme: dark を局所適用する設計も有効です。
「ブランドのアクセントをネイティブにも」という要望には、リンクと同じ light-dark() トークンへ accent-color を結び付けましょう。ダークモードでスライダだけシステム紫へ戻ると、レビュアの信頼を一瞬で失います。CMS が露出するネイティブコントロールを一覧した小さなフィクスチャページを、一度 45 分 かけて作れば、以降のリリースでは再利用できます。
静的ページに SVG チャートを埋め込む場合、エクスポートツール由来の fill 直書きは CSS 変数を無視することがあります。軸線は currentColor ストロークに寄せるか、ビルド時に HTML パーシャルと同じ手順でパレット置換してください。
ゼブラストライプの表は、絶対指定の明/暗ペアより light-dark() 由来の行背景の方が、ダークで境界が消える事故を減らせます。
マーケ埋め込み(iframe)は親の color-scheme を無視することがあります。どのサードパーティが隔離ラッパーを要するかをドキュメント化しておくと、緊急時の切り分けが速いです。
クラウド Mac mini 上の Safari QA
Playwright の WebKit は構文解析には強い一方、コントラスト強化 や 透明度を減らす が重なったときの半透明カードの振る舞いまでは再現が薄い場面があります。リリースごとに Apple シリコン上の Safari で 20~35 分 を確保し、契約上のサインオフは安定版、回帰切り分けは Technology Preview、という二段構えが現実的です。
ハード調達が遅れるなら、スプリント単位でクラウド Mac mini を借りるのが費用対効果に優れます。MacHTML の Apple Silicon ホストは多くの場合 日 $16.9 前後 で、静的バンドルを scp で流し込む SSH と、インタラクティブにテーマを眺める VNC がセットになっています。夜間にノート PC を送るより安く、証拠の画面録画も取りやすいです。
本番と同じ font-feature-settings、Web フォント URL、必要なら color-mix() の組み合わせまでミラーしてください。フォントが違うと輝度知覚が変わり、コントラスト計算の前提が静かに崩れます。
システム外観の切替は 120 fps で録画すると、ナビのクロームと本文背景の一フレーム不一致を、口頭論争ではなく映像で終わらせられます。
コントラスト、強制配色、透明度の低減
法務や財務レビューでは、ライトとダークの並列 PDF が求められることが増えています。同じ静的 URL を、ヘッドレス Chrome の配色エミュレーションで吐き出す PDF と、Safari から印刷する PDFで比較し、輝度が 4% 以上ズレるなら、まだ UA ヒューリスティクスに依存しているサインです。
macOS の コントラストを増やす を有効にすると、ガラス調パネルが平坦化し、装飾だと思っていた境界トークンが突然クリティカルになります。
prefers-reduced-transparency では、同じ light-dark() トークンから不透明面を組み立て直し、視覚効果を落としても情報の階層が保たれるようにします。
状態表現は色だけに頼らず、字重やアイコンを添えて、強制配色ユーザーでもエラーが読めるようにしてください。
静的パイプライン向けロールアウト
CDN 運用者と調整してください。新トークンを参照する HTML が先に出て、古い CSS だけが残ると、ユーザーには「無装飾の本文」が見えます。color-scheme を変えるときは HTML と CSS のキャッシュキーを同時にパージし、パージ後 15 分 はエッジ POP の取りこぼしを監視するのが安全です。
- ビジュアル差分がステージングで通るまで、本文に一時的な
data-属性でゲートする。 - Playwright のスナップショットは同じ幅でライト/ダーク双方を取り、ビューポート幅の 2% を超えるドリフトでアラートする。
- どのロケールから先に出すか文書化する。CJK 市場は句読点まわりのコントラスト問題を早めに表面化しがちです。
- Lighthouse と Axe のトレースは、Safari の画面録画と同じセッション ID で保管し、監査証跡を揃える。
よくある質問
prefers-color-scheme を完全に捨ててよいですか?
まだ無理です。@supports not の内側に残し、計測上の非対応トラフィックが無視できるまで温存してください。
light-dark() と OKLCH は併用できますか?
はい。関数を入れ子にします:light-dark(oklch(0.95 …), oklch(0.2 …))。Safari のリリースノートで組み合わせの注意を確認してください。
Safari の QA 時間の目安は?
テーマ切替とフォームで 20~35 分、リンク周りの VoiceOver でさらに 10 分程度を足すと安心です。
Apple Silicon Mac mini は、WebKit の配色議論を終わらせる最短経路です。ネイティブの色管理、長時間キャプチャでも読みやすいサーマル、Linux だけの CI では再現が難しい macOS のアクセシビリティ切り替えが揃います。MacHTML は SSH/VNC 付きのクラウド Mac mini で light-dark()、color-scheme、スティッキークロームを別の CapEx なしに検証できます。スプリントで確保し、証拠が取れたら解放する運用が現実的です。
クラウド Mac mini で Safari テーマ QA
Apple Silicon をレンタルし、light-dark()・ネイティブコントロール・アクセシビリティ切り替えを実 WebKit で検証できます。