カラーコントラストとアクセシビリティ
問題
カラーコントラストはウェブ上で最も多いアクセシビリティ違反です。WebAIMの年次分析では、ホームページの80%以上に低コントラストのテキストがあることが一貫して報告されています。AIエージェントは白い背景に薄いグレーのテキスト、コントラスト要件を満たさないプレースホルダーテキスト、読みやすさよりも美観を優先した装飾的な色選び、周囲のコンテンツと区別できないインタラクティブ要素を持つデザインを頻繁に生成します。その結果、ロービジョン、色覚異常、または困難な閲覧条件(明るい日差し、暗い画面)のユーザーにとって読みにくい、または読めないテキストになります。
解決方法
WCAG(Web Content Accessibility Guidelines)は、前景色と背景色の間の最小コントラスト比を定義しています。これらの比率を満たすことで、視覚障害を持つ方を含む、最も幅広いユーザーにとってテキストが読みやすくなります。
WCAG コントラスト要件
| レベル | 通常テキスト(< 18pt / < 14pt 太字) | 大きなテキスト(≥ 18pt / ≥ 14pt 太字) | UIコンポーネント |
|---|---|---|---|
| AA | 4.5:1 | 3:1 | 3:1 |
| AAA | 7:1 | 4.5:1 | — |
「大きなテキスト」は 18pt(24px)以上、または 14pt(18.67px)太字以上と定義されています。
コード例
安全なカラーの組み合わせ
/* PASS AA — dark text on light background */
.text-on-light {
color: oklch(25% 0.02 264); /* ~#1a1a2e */
background: oklch(98% 0.005 264); /* ~#f8f8fc */
/* Contrast ratio: ~15:1 ✓ */
}
/* PASS AA — light text on dark background */
.text-on-dark {
color: oklch(90% 0.01 264); /* ~#e0e0f0 */
background: oklch(18% 0.015 264); /* ~#1e1e30 */
/* Contrast ratio: ~11:1 ✓ */
}
/* FAIL AA — light gray on white */
.text-low-contrast {
color: oklch(70% 0 0); /* ~#a0a0a0 */
background: oklch(100% 0 0); /* white */
/* Contrast ratio: ~2.6:1 ✗ */
}
良いコントラスト vs 悪いコントラスト
アクセシブルなブランドカラー
:root {
/* Brand blue — test against both light and dark backgrounds */
--brand: oklch(45% 0.2 264);
/* ✓ On white (contrast ~7:1) */
--brand-on-light: oklch(45% 0.2 264);
/* ✓ On dark bg (contrast ~5:1) - lighter variant needed */
--brand-on-dark: oklch(72% 0.15 264);
}
/* Apply contextually */
.light-section a {
color: var(--brand-on-light);
}
.dark-section a {
color: var(--brand-on-dark);
}
アクセシブルなプレースホルダーテキスト
/* WRONG: Default placeholder is typically too light */
input::placeholder {
color: oklch(75% 0 0); /* ~#b0b0b0 — fails 4.5:1 on white */
}
/* CORRECT: Darker placeholder that passes contrast */
input::placeholder {
color: oklch(48% 0 0); /* ~#6b6b6b — passes 4.5:1 on white */
}
/* Always provide visible labels — don't rely on placeholder as label */
アクセシブルな無効状態
/* Disabled elements are exempt from WCAG contrast requirements,
but they should still be distinguishable from the background */
.button:disabled {
color: oklch(60% 0 0);
background: oklch(90% 0 0);
cursor: not-allowed;
/* Contrast ~2.5:1 — enough to see it exists, clearly different from active buttons */
}
/* But NEVER use low contrast for text users need to read */
十分なコントラストのフォーカスインジケーター
/* Focus ring must have 3:1 contrast against adjacent colors */
:focus-visible {
outline: 2px solid oklch(45% 0.2 264);
outline-offset: 2px;
/* The 2px offset creates a gap, so contrast is measured against the background */
}
/* High-contrast focus ring for dark backgrounds */
.dark-section :focus-visible {
outline: 2px solid oklch(80% 0.15 264);
outline-offset: 2px;
}
リンクのコントラスト
/* Links in body text need 3:1 contrast against surrounding text (WCAG 1.4.1)
OR a non-color visual indicator (underline) */
/* Option 1: Underlined links (recommended — color alone is not enough) */
a {
color: oklch(45% 0.2 264);
text-decoration: underline;
}
/* Option 2: If removing underline, ensure 3:1 contrast with body text
AND add non-color indicator on hover/focus */
a {
color: oklch(45% 0.2 264); /* Must be 3:1 against body text color */
text-decoration: none;
}
a:hover,
a:focus {
text-decoration: underline; /* Non-color indicator */
}
色だけに頼ってはいけない
/* WRONG: Only color differentiates error state */
.input-error {
border-color: red;
}
/* CORRECT: Color plus additional visual indicator */
.input-error {
border-color: oklch(55% 0.22 25);
border-width: 2px; /* Thicker border */
box-shadow: 0 0 0 1px oklch(55% 0.22 25); /* Additional visual cue */
}
<!-- Also include text indication -->
<input class="input-error" aria-describedby="error-name" />
<p id="error-name" class="error-message">Name is required</p>
OKLCH でのコントラストテスト
OKLCHの明度を大まかなコントラスト予測指標として使用:
:root {
/* Rule of thumb: ~45-50 OKLCH lightness units between bg and text
roughly corresponds to WCAG AA 4.5:1 contrast */
--bg-light: oklch(97% 0.005 264); /* L: 97% */
--text-on-light: oklch(25% 0.02 264); /* L: 25% — delta: 72% ✓ */
--bg-dark: oklch(15% 0.01 264); /* L: 15% */
--text-on-dark: oklch(90% 0.01 264); /* L: 90% — delta: 75% ✓ */
/* Muted text needs extra care */
--text-muted-light: oklch(45% 0.02 264); /* L: 45% — delta from bg: 52% ✓ */
--text-muted-dark: oklch(65% 0.01 264); /* L: 65% — delta from bg: 50% ✓ */
}
注意:OKLCHの明度差は近似値であり、実際のコントラスト比テストの代替ではありません。必ずコントラストチェッカーツールで確認しましょう。
システムレベルのハイコントラストサポート
/* Respect Windows High Contrast / forced-colors mode */
@media (forced-colors: active) {
.button {
border: 2px solid ButtonText;
/* Browser enforces system colors — don't fight it */
}
.icon {
fill: ButtonText; /* Use system color keywords */
}
}
AIがよくやるミス
- 白い背景に薄いグレーテキスト(
#999、#aaa、#bbb)を使っている — これらはすべてWCAG AA(4.5:1)に不合格 - コントラストを満たさない薄いグレーのプレースホルダーテキストを設定し、そのプレースホルダーを唯一のラベルとして使用している
- テキストとボタンのコントラストが不十分なカラーボタンを生成している(例:薄い黄色のボタンに白いテキスト)
- 情報を伝える唯一の手段として色を使っている — エラー状態が赤色のみ、リンクが色のみで区別されている
- インタラクティブ状態のコントラストをテストしていない:hover、focus、active の色もコントラスト比を満たす必要がある
- 視覚的な階層のためにテキストに
opacityを適用している(低コントラストの色を使う代わりに)— opacity は背景に応じて予測不能にコントラストを下げる - 「ダークモード = アクセシブル」と思い込んでいる — ダークモードにも独自のコントラスト検証が必要で、多くのダークテーマはコントラスト要件を満たしていない
- 継承された値がすべてのコンテキストで十分なコントラストを提供することを確認せずに
color: inheritやcurrentColorを使っている - ボーダー、アイコン、インタラクティブ要素の境界に対する非テキストコントラスト要件(3:1)を無視している
- 透明性を含む実際のレンダリング色にWCAGコントラスト比が適用されることを無視している — 変化する背景上の半透明テキストレイヤーは一部のエリアでパスし、他のエリアで不合格になる可能性がある
使い分け
コントラストチェックはデザインのすべてのテキストとUI要素で行うべきです:
- 本文テキスト: 背景に対して4.5:1(AA)または7:1(AAA)を満たす必要がある
- 大きな見出し(24px以上、または18.67px太字以上): 3:1(AA)または4.5:1(AAA)を満たす必要がある
- インタラクティブコントロール: ボーダー、アイコン、フォーカスインジケーターは隣接する色に対して3:1を満たす必要がある
- テキスト内のリンク: 周囲の本文テキストに対して3:1のコントラストが必要、またはアンダーラインのような非カラーインジケーターを使用
- フォームラベルとヘルプテキスト: 標準的なテキストコントラスト要件を満たす必要がある
- プレースホルダーテキスト: 必要な情報を伝える場合は4.5:1を満たす必要がある(より良い方法:常に可視ラベルを使用)
推奨テストツール
- WebAIM Contrast Checker — 手動チェック用
- OKLCH Color Picker — OKLCH値での視覚的なコントラストプレビュー
- Chrome DevTools — 要素検査でテキストのコントラスト比を表示
- Lighthouse — 自動監査でコントラストの問題をフラグ
- Colour Contrast Analyser (CCA) — スポイト付きデスクトップアプリ
参考リンク
- MDN: Color contrast — Accessibility
- WebAIM: Contrast and Color Accessibility
- WCAG 2.2: Success Criterion 1.4.3 Contrast (Minimum)
- WCAG 2.2: Success Criterion 1.4.11 Non-text Contrast
- Color Contrast Accessibility: Complete WCAG 2025 Guide — AllAccessible
- 3 color contrast mistakes designers still make — UX Collective