ポロねぎのグリル、ロメスコソース添え
トピックを検索
ダークモードでコントラストが足りなくなる文字とアイコン
ダークテーマが背景と本文の色だけを切り替え、補足のグレーの文字とSVGアイコンはライトテーマの色のまま残すため、暗いカードの上でかすんでしまう
.meta { color: #6b7280; } 問題
ダークモードを使う弱視の利用者が、レシピの所要時間を読みづらく、保存と共有のボタンも見つけにくい
レシピサイトに、端末の設定に合わせて切り替わるダークテーマがあります。デザインファイルでは、大きな面の色を入れ替えてダーク版を作りました。ページとカードは薄いグレーと白から深いスレート色に、タイトルは黒に近い色から白に近い色に変わります。タイトルの下で所要時間と人数を示すグレーの行と、その横の保存・共有のアイコンは、ライト版の色をそのまま使いました。ライトテーマでは、デザインの狙いどおり控えめで、しかもはっきり見えます。開発者はそのとおりに実装し、ページ、カード、タイトルの色をトークンにして、prefers-color-scheme: dark のブロックで定義し直しました。
端末をダークモードにすると、サイトも切り替わります。タイトルは問題なく読めます。ところが、その下の「25分 · 4人分」は暗いカードの上の中間のグレーになり、保存と共有のアイコンは暗いグレーの上の暗いグレーになります。場所を知っている人には見えても、知らない人には見えません。
ダークテーマが定義し直すのは、トークンになっている色だけです。グレーは .meta に16進数の値で直接書かれ、アイコンの色は各SVGの fill 属性に書かれているため、テーマが変わっても変わりません。
- 所要時間の行の
#6b7280は、白いカードの上で4.83:1、#1f2937のカードの上で3.04:1です。この大きさの文字に、WCAG 1.4.3は4.5:1を求めています。 - アイコンの
#374151は、白の上で10.31:1、暗いカードの上で1.42:1です。各ボタンが何かを示すのはアイコンだけなので、1.4.11は周りの色に対して3:1を求めています。
どちらの基準も、ページが実際に表示する色で測ります。ダークモードの利用者には、このページはダークテーマで表示されます。切り替えているのはブラウザーではなく、サイト自身のCSSです。画面上の色はどれも、サイトが指定した色か、ダークテーマ用に指定しなかった色です。
システムの設定に合わせるサイトは、ダークモードの利用者全員にダークテーマを表示します。夜だけ自動でダークモードになるよう設定したスマートフォンでも同じです。読者の多くは、このサイトのテーマを自分で選んだわけではありません。
10グループ中1グループに影響
- 全盲 (影響なし)
- 弱視 (影響あり)
- 色覚 (影響なし)
- ろう (影響なし)
- 難聴 (影響なし)
- 発話 (影響なし)
- 手の操作 (影響なし)
- 筋力・可動域 (影響なし)
- 認知 (影響なし)
- 光過敏 (影響なし)
- 視覚が限られる 弱視の人の中には、白い画面がまぶしいためにダークモードをオンにする人がいます。暗いカードの上では所要時間が3.04:1、アイコンが1.42:1まで下がるため、拡大鏡を使っても時間は読みにくく、アイコンのボタンは見つけにくくなります。
axeを含む自動チェックは、ブラウザーが今使っている配色でページを測ります。ヘッドレスブラウザーは、指定しない限りライトモードです。ライトモードではこのページのどの色も基準を満たすため、チェックの結果は問題なしになります。EaseWebの診断は、ダークモードで色が変わるページについてはダークモードをエミュレートして測り直しますが、対象はシステムの設定に合わせるテーマだけです。サイト独自の切り替えボタンでしか有効にならないテーマには届きません。ダークテーマのCSSを読んでも、修正前のコードの問題は見つかりません。ダークのブロックには、用意されたトークンについては漏れがなく、足りないのはコンポーネントの側だからです。AIが生成するダークテーマも同じところで止まることがあり、背景と本文の色は切り替えても、カードの中のグレーやアイコンの塗りはそのまま残ります。
試してみる
ダークモードをオンにして、各レシピの所要時間を読み、保存ボタンを探してみましょう
スイッチを入れると、端末をダークモードにしたときの見た目になります。カードが暗くなっても、「25分 · 4人分」を読み、保存と共有のアイコンを見つけられますか?
問題あり 修正できますか?
レモンと大麦のリゾット
修正方法
文字とアイコンのすべての色に、ダーク用の値を持たせる
<article class="recipe"> <h2>ポロねぎのグリル、ロメスコソース添え</h2> <p class="meta">25分 · 4人分</p> <button type="button" class="icon-button" aria-label="保存"> <svg viewBox="0 0 24 24" aria-hidden="true"> <path fill="#374151" d="…"/> </svg> </button> <button type="button" class="icon-button" aria-label="共有"> <svg viewBox="0 0 24 24" aria-hidden="true"> <path fill="#374151" d="…"/> </svg> </button></article>問題点2点
ライトテーマでは基準を満たします。ダークテーマでは次のようになります。
- 所要時間の行は
#6b7280のままで、暗いカードの上で3.04:1です。 - 保存と共有のアイコンは
fill="#374151"のままで、暗いカードの上で1.42:1です。
すべての色にテーマのトークンを使う
<article class="recipe"> <h2>ポロねぎのグリル、ロメスコソース添え</h2> <p class="meta">25分 · 4人分</p> <button type="button" class="icon-button" aria-label="保存"> <svg viewBox="0 0 24 24" aria-hidden="true"> <path fill="currentColor" d="…"/> </svg> </button> <button type="button" class="icon-button" aria-label="共有"> <svg viewBox="0 0 24 24" aria-hidden="true"> <path fill="currentColor" d="…"/> </svg> </button></article>修正の手順4ステップ
- コンポーネントが使う役割ごとにトークンを用意します。ここでは控えめな文字の
--mutedとアイコンの--iconで、値はライトテーマのものです。ライトテーマの見た目は変わりません。 - 2つのトークンをダークのブロックで定義し直し、暗いカードの上で測ります。グレーは
#9ca3af(5.78:1)、アイコンは#d1d5db(9.96:1)に明るくなります。 .metaの色を、16進数の値からvar(--muted)に変えます。- SVGのパスを
fill="currentColor"にし、.icon-buttonの色を--iconから取ります。アイコンはどちらのテーマでも、ボタンの色で描かれます。
これで修正前の例は直り、どちらのテーマでも1.4.3と1.4.11を満たします。ダーク版でも、控えめなグレーの行と柔らかいアイコンというデザインはそのままで、一段明るくなるだけです。
どちらも基準を満たし、どちらも各色にダーク用の値を持たせます。違うのは、その値を置く場所です。テーマのトークンはすべての色を1か所にまとめるため、デザインシステムの配色とコントラスト比をまとめて確認でき、トークンを使う新しいコンポーネントは、誰も意識しなくても両方のテーマで正しくなります。複数のコンポーネントが同じグレーを共有するなら、トークンを選びます。light-dark() は各組をコンポーネントの1行に置くため、色にダーク用の値があることがレビューですぐ分かり、2つ目のブロックも要りません。独自の色を持つコンポーネントや、色の数が少ないサイトに向いています。どちらの場合も、アイコンは currentColor にする必要があります。SVGに直接書かれた色には、トークンも組も届かないからです。
各色は、ページの背景だけでなく、ダークテーマで置かれるすべての背景の上で測ります。ダークテーマでは、明るい面で奥行きを表すことが多いため、#111827 のページの上で基準を満たすグレーも、より明るいカード、バナー、メニューの上ではコントラストが下がり、届かないことがあります。
システムの設定ではなく、サイト独自の切り替えボタンで変わるテーマにも、同じ値が必要です。ボタンでルートに data-theme="dark" などの属性を設定し、メディアクエリーと同じトークンをそのセレクターでも定義し直すか、ボタンでルートの color-scheme を切り替えて light-dark() を従わせます。WCAGの1.4.3の解説ページは、利用者が選んだ色が基準を下回ることを「必要な値に戻す仕組みがあれば」認めています。ライトテーマにワンクリックで戻せる切り替え式のダークテーマがこれに当たるかどうかは、WCAGでもまだ結論が出ていません。システムの設定に合わせるテーマには、そのワンクリックがありません。ダークモードの利用者全員が受け取るページそのものです。いずれにしても、読むためにダークモードを必要としている人もいるため、提供するテーマはすべて測ってください。
Tailwindでは、色のユーティリティごとに dark: の組が必要です(text-gray-500 dark:text-gray-400)。1つでも書き忘れると、ライトの値のまま残ります。色をダークテーマで変わるテーマ変数として定義すれば、ユーティリティが上のトークンと同じく役割を表すようになり、書き忘れる組がなくなります。
<img> のファイルとして表示するアイコンは、currentColor を使えません。ページのCSSがファイルの中まで届かないためです。単色のアイコンはSVGとしてインラインで書くか、ダークテーマ用に別のファイルを用意します。SVGファイルの中に prefers-color-scheme のクエリーを書く方法もありますが、Safariは <img> で読み込んだSVGでは、このクエリーを長く無視してきました。ロゴの文字は1.4.3の対象外ですが、黒いロゴが暗いページに置かれると、表示が壊れたように見えます。<picture> に <source media="(prefers-color-scheme: dark)"> を加え、明るい版を指定します。
フォーカスの枠も同じ問題を起こします。#1a4fd0 の枠は白の上で6.83:1ですが、#1f2937 のカードの上では2.15:1です。枠にもトークンか組を用意します。iframeで埋め込んだウィジェットは、ウィジェット側の配色のまま表示されます。ダークの設定があれば使い、なければ明るいまま残します。ウィジェット自体の色が基準を満たしていれば問題ありません。
デザインの案
ダークテーマも、控えめなまま読みやすくできる
レシピサイトのダークテーマの描き方を6通り示します。それぞれを読み、Tabでリンクや入力欄に移動してみてください。3つはひと目で読め、3つは見分けにくくなっています。
デザインファイルで
- ダーク版はページの色だけでなく画面ごとに描き、文字のスタイル、アイコン、入力欄の枠のそれぞれにダーク用の色を決める。
- 各色の横に、そのテーマで置かれる面に対して測ったコントラスト比を書く。文字は最低4.5:1、アイコンと入力欄の枠は最低3:1。
- 色には「控えめな文字」「アイコン」のように役割で名前を付け、どの名前にもライトとダークの値を持たせる。
- ロゴとイラストも暗いページの上に置いて確認し、暗い版が見えなくなるところには明るい版を用意する。
合格
- ほぼ黒の背景に、白に近い文字 #18181bの背景に、#e4e4e7のタイトル(13.96:1)と#a1a1aaの所要時間(6.91:1)を置きます。真っ黒に真っ白より柔らかく、どの行も4.5:1を大きく上回ります。
- 明るいカードで奥行きを出す #0f172aの背景に#1e293bのカードを置き、影を使わずに奥行きを出します。#94a3b8の所要時間は、比率が最も低くなるカードの上で測ります。ページの上では6.96:1、カードの上では5.71:1です。
付け合わせは ロメスコソースのレシピがおすすめです。
ダークでは一段明るいアクセント 白の上で#2563eb(5.17:1)のリンクを、#1f2937のカードの上では#60a5fa(5.77:1)にします。ブランドの青に見えるまま、下線も残します。
不合格
- 白40%の所要時間WCAG 1.4.3 不透明度40%の白は、どの暗い面の上でも柔らかく見えますが、#18181bの上では#747476になり、3.80:1です。不透明な#a1a1aaなら、同じ控えめな見た目のまま6.91:1になります。
付け合わせは ロメスコソースのレシピがおすすめです。
ライトテーマの青のままWCAG 1.4.3 #2563ebは白の上では5.17:1で基準を満たしますが、#1f2937のカードの上では2.84:1です。リンクは青いままですが、読みにくくなります。- 淡い塗りだけの検索欄WCAG 1.4.11 #18181bの背景の上の#27272aの塗りは1.19:1で、欄の境目が見分けられません。#71717aの枠(3.67:1)を付ければ、同じ柔らかい塗りのまま欄が分かります。
修正の確認
5項目、マウス不要
確認方法: ダークモード、コントラストの測定、拡大表示
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。テーマのトークンや共通のコンポーネントのスタイルを変更した際は、再度確認します。
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。色の値とトークン名は例のため、実際の配色を実際の背景で測定してください。ライトテーマでのコントラスト比は、ブランドカラーや写真の上でコントラストが足りない文字とコントラストが足りない入力欄・アイコン・フォーカス枠で扱います。Windowsのコントラスト テーマは、サイトの色を利用者が選んだ色に置き換えるもので、別の問題です。ハイコントラストモードで消えるフォーカス・アイコン・選択状態で扱います。必要とする人と一緒に、両方のテーマでページ全体を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
参考資料
- WCAG Understanding: contrast-minimum(新しいタブで開きます)
- WCAG Understanding: non-text-contrast(新しいタブで開きます)
- developer.mozilla.org: prefers-color-scheme(新しいタブで開きます)
- developer.mozilla.org: light-dark(新しいタブで開きます)
- developer.mozilla.org: color-scheme(新しいタブで開きます)
- hidde.blog: making-single-color-svg-icons-work-in-dark-mode(新しいタブで開きます)
EaseWebのサービス
修正した問題を、次のリリースで再発させない
このガイドのような修正方法を、コーディングエージェントが従うルールと、CIのチェックに組み込みます。あわせて定期的に、キーボードとスクリーンリーダーで手動の再テストを行います。