この記事の対象: 配色を自分で決めて実装までやるWeb制作者
読了時間: 約12分
コントラスト比のチェックは、デザインを「安全側に寄せて地味にする」ための作業ではありません。文字が読めるかどうかを数値で確かめ、色そのものを変えずに基準を満たす逃げ道を知っておくための作業です。淡いブランドカラーを渡されたときに「この色では基準に届きません」と返すのと、「この色のままで、文字側と面積の持たせ方を変えれば通ります」と返すのでは、案件の進み方がまるで違います。
この記事では、WCAG の 4.5:1 / 3:1 が何を指しているのかを整理したうえで、ブラウザの開発者ツールで実際に測る手順、そしてブランドカラーを維持したまま基準を満たすCSSを載せます。測り方だけでなく、どの場面で妥協してよくて、どの場面では絶対に妥協できないかまで言い切ります。
コントラスト比とは何を測っている数字か

4.5:1 と 3:1 の境目
WCAG 2.1 の達成基準 1.4.3(最低限のコントラスト・レベルAA)が要求しているのは、次の2つです。
| 対象 | 必要な比率 |
|---|---|
| 本文などの通常サイズの文字 | 4.5:1 以上 |
| 大きな文字 | 3:1 以上 |
| UIコンポーネントの境界・グラフの線(1.4.11) | 3:1 以上 |
| 装飾目的の文字・ロゴタイプ | 基準の対象外 |
ここで言う「大きな文字」の定義は、18pt(24px)以上、または 14pt(約18.66px)以上の太字です。見出しが 24px 以上あるなら 3:1 で通りますが、サブ見出しを 20px のレギュラーで組んだ場合は通常サイズ扱いになり 4.5:1 が必要になります。この境目を知らないまま「見出しだから緩いはず」と判断すると、ちょうど落ちる位置に設計してしまいます。
3:1 で足りる
- 24px 以上のレギュラー
- 18.66px 以上の太字
- ボタンやフォームの枠線
4.5:1 が必要
- 16px の本文
- 20px のレギュラー見出し
- 14px のキャプション・注記
落とし穴になるのは右側の2番目です。20px のレギュラーは見た目に「大きい文字」なので緩いほうで判断されがちですが、24px に届いていないので 4.5:1 が要ります。
数字は「明るさの差」で、色の違いではない
コントラスト比は相対輝度(relative luminance)の比です。計算式は (L1 + 0.05) / (L2 + 0.05) で、L1 が明るい側、L2 が暗い側の相対輝度。最小は 1:1(同じ色)、最大は 21:1(純黒と純白)です。
重要なのは、色相が違っても明るさが近ければ比率は上がらないという点。鮮やかな赤と鮮やかな緑は人間の目にはまったく別の色に見えますが、輝度が近ければコントラスト比は 1.x:1 にしかなりません。「はっきり違う色なのに警告が出る」という状況はここで起きます。
逆に言えば、色相と彩度は保ったまま明度だけ動かせば比率は改善できる。これが後半の「色を変えずに済ませる」という発想の土台です。
彩度の高い色では数字と体感がズレる
WCAG 2.x の計算式は彩度を考慮していません。そのため、鮮やかな純青の上の白文字のように、数値上は 4.5:1 を超えているのに実際には目が疲れる組み合わせが通ってしまいます。逆に、彩度の低いグレー同士は数値どおりの読みやすさになります。
後継の評価方法として APCA(Accessible Perceptual Contrast Algorithm)が WCAG 3 の検討で挙がっていますが、WCAG 3 自体はまだ勧告になっておらず、納品物の判定基準として使えるのは依然として WCAG 2.1 の 4.5:1 / 3:1です。APCA は「数値は通ったが目が痛い」という体感を裏付ける材料として使うに留め、クライアントへの報告は WCAG 2.1 の数字で出すのが実務的です。
ブラウザの開発者ツールでコントラスト比を確認する

Chrome / Edge の Inspect で見る最短手順
カラーピッカーに比率が出るので、実装済みの画面はツールを足さずに測れます。
4番目がいちばん使えます。カラーピッカーのグラデーション内に引かれる曲線は「ここより暗くすれば AA を満たす」という境界線で、色相のつまみを動かさずに明度のつまみだけ線の向こう側へ落とせば、色味を保ったまま通るところまで一目で分かります。線が2本出る場合、浅い側が AA(4.5:1)、深い側が AAA(7:1)です。
ここで出る数値は「DevToolsが背景として検出した色」との比なので、半透明の要素や背景画像の上に乗った文字では正しく出ないことがあります。その場合は次の方法に切り替えます。
ページ全体をまとめて洗い出す
1要素ずつ見ていては案件規模では終わらないので、面で拾う手段を併用します。
- Chrome の Lighthouse: アクセシビリティ監査に「背景色と前景色のコントラスト比が十分ではありません」という項目があり、該当要素が一覧で出ます。ビューポート内にある要素が対象なので、フッターやモーダル内は別途スクロール・展開して再実行が必要です。
- Chrome の CSS Overview: 「Contrast issues」に、ページ内で使われている色の組み合わせごとに問題箇所がまとまります。同じ色のペアが何十箇所で使われているときは、こちらのほうが直す単位と一致します。
- axe DevTools / WAVE などの拡張: ルールベースで指摘が出ます。ただし拡張はブラウザのバージョンで挙動が変わるため、納品チェックに使うなら使用バージョンを控えておくこと。
- Firefox のアクセシビリティインスペクタ: 「すべての問題をチェック」でコントラストを含めた指摘が出ます。背景画像の上の文字について「判定できない」と明示してくれるのが実務では助かります。
機械で拾えないのは次の3つです。手で見るしかありません。
- 背景画像・動画の上に乗った文字(どのピクセルと比べるかが決まらない)
- ホバー・フォーカス・押下中など、状態が変わったときの色
- ダークモード切り替え後の色(
prefers-color-schemeを切り替えて測り直す)
Chrome なら DevTools の「Rendering」パネルから prefers-color-scheme をエミュレートできるので、ダークモードを実装したら必ず切り替えた状態で Lighthouse を再実行します。ライトモードだけ通してダークが落ちている案件は珍しくありません。
実装前にパレットの段階で測る
実装してから落ちているのが分かると、構造ごと直すことになります。配色を決める段階で明度の段を作っておくのが確実です。
やり方は単純で、ブランドカラーの色相・彩度を保ったまま明度を 5〜10% 刻みで並べ、それぞれが白背景・黒文字に対して何:1 になるかを一覧にしてから使い先を割り当てます。「この色は面にしか使わない」「文字に使えるのはこの段から下」と決めてしまえば、実装中に迷いません。
色相ごとの効き方や使いどころを整理するときは、同系色の事例をまとめた記事も合わせて見ると判断が早くなります。
淡いブランドカラーで基準に届かないときの逃げ道

ここが本題です。「ブランドカラーが淡いベージュで、その上に文字を置くと 2.8:1 にしかならない」という状況で、色を変えずに通す手が4つあります。
手1: 色を面に、文字は別の色に分ける
いちばん効くのがこれ。ブランドカラーを背景・区切り・アイコンの塗りに回し、文字色は同じ色相の暗い段に置き換える。ブランドカラーそのものは画面から消えず、文字は通ります。
:root {
/* ブランドカラー(淡い)— 面に使う */
--brand: #e8d9c3;
--brand-tint: #f7f1e8;
/* 同じ色相で明度だけ落とした段 — 文字に使う */
--brand-ink: #5a4324; /* #f7f1e8 に対して約 7.3:1 */
--brand-ink-weak: #7a6340; /* #f7f1e8 に対して約 4.6:1 */
}
.card {
background: var(--brand-tint);
border: 1px solid var(--brand);
border-radius: 12px;
padding: 24px;
}
.card__title {
color: var(--brand-ink);
font-size: 1.25rem;
font-weight: 700;
margin: 0 0 8px;
}
.card__body {
color: var(--brand-ink);
font-size: 1rem;
line-height: 1.8;
margin: 0;
}
.card__note {
/* 注記は小さいので弱い段でも 4.5:1 を確保した色を使う */
color: var(--brand-ink-weak);
font-size: 0.875rem;
margin: 16px 0 0;
}
ポイントは --brand-ink-weak の扱いです。「補助情報だから薄くていい」と彩度と明度を両方落とすと一発で落ちます。弱く見せたいなら色を薄くするのではなく、サイズを下げるか文字間を変える。色は 4.5:1 を保ったままにします。
変数名を --brand-light / --brand-dark ではなく「面に使う」「文字に使う」が分かる名前にしておくと、後から他の人が触っても誤用が起きません。
手2: ボタンは背景色を保ったまま文字色を反転させる
淡い背景のボタンに白文字を置くのは、ほぼ通りません。白を諦めて、暗い文字にします。
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 48px;
padding: 0 28px;
border: 1px solid #c9b48f; /* 背景との境界も 3:1 を意識して置く */
border-radius: 8px;
background: #e8d9c3;
color: #3d2c14; /* #e8d9c3 に対して約 9.0:1 */
font-size: 1rem;
font-weight: 700;
text-decoration: none;
cursor: pointer;
transition: background-color .2s ease, border-color .2s ease;
}
.btn:hover {
background: #dcc8a9;
border-color: #b49c71;
}
.btn:focus-visible {
/* 枠線ではなく outline で出す。レイアウトがずれない */
outline: 3px solid #3d2c14;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.btn {
transition: none;
}
}
中間的な明るさの背景色は、白文字と黒文字のどちらでも 4.5:1 を超えないことがあります。その場合は背景色の明度を数%だけ動かして、どちらかに寄せる。ブランドカラーの定義を書き換えるのではなく、ボタンという特定の用途だけ #e8d9c3 を少し濃くする、という処理であればブランド側の了解も取りやすいです。
:focus-visible を outline で書いているのは、border を足すと要素の寸法が変わってレイアウトが跳ねるためです。outline-offset を付けておくと、ボタンの色と干渉せず枠が見えます。
手3: 画像の上の文字は、画像を暗くせずに帯を敷く
背景写真の上に白文字を置く構成では、画像の明るい部分で基準を割ります。よく見るのは filter: brightness() で画像全体を暗くする処理ですが、フィルターは再描画のたびに走るので、スクロールやアニメーションと組み合わせると描画負荷が見えるかたちで乗ります。大きなヒーロー画像ほど影響が出ます。
軽いのは linear-gradient を重ねる方法です。合成はブラウザ側で済み、画像のデコード結果を加工しません。
.hero {
position: relative;
min-height: 60svh;
display: grid;
place-items: center;
background-image:
linear-gradient(to top, rgba(26, 18, 8, .72), rgba(26, 18, 8, .25)),
url("/images/hero.webp");
background-size: cover;
background-position: center;
}
.hero__inner {
max-width: 44rem;
padding: 48px 24px;
text-align: center;
}
.hero__title {
color: #ffffff;
font-size: clamp(1.75rem, 4vw, 3rem);
line-height: 1.4;
letter-spacing: .02em;
margin: 0 0 16px;
/* 文字の縁取りは保険。これに依存して比率を甘く見ない */
text-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}
.hero__lead {
color: #f4efe6;
font-size: 1rem;
line-height: 1.9;
margin: 0;
}
グラデーションを「文字が乗る側だけ濃く」しているのは、写真の見せたい部分を潰さないためです。下側に文字を置く構成なら to top、上側なら to bottom にします。
測るときは、グラデーションを重ねた状態の実際のピクセル色と文字色で比較します。DevTools のカラーピッカーはここを正しく拾えないので、スクリーンショットを撮ってから画面上の色を拾う方法に切り替えてください。macOS のデジタルカラーメーターや、スポイト機能のあるツールで実際の表示色を取るのが確実です。
画像自体の重さにも触れておくと、ヒーロー画像は表示面積が大きいぶん LCP に直結します。WebP か AVIF で出し、width / height を指定して CLS を防ぎ、ファーストビューの画像には loading="lazy" を付けない(遅延で LCP が悪化する)。この3点は配色の話と独立していますが、ヒーローを触るときに同時に確認する箇所です。
手4: 面積を分けて、ブランドカラーを「読ませない場所」に集める
文字と背景の関係だけで解けないときは、構成で解きます。
淡い色をそのまま使ってよい場所
- セクション背景
- 大きな面の塗り分け
- 装飾の図形・罫
- 見出し周りのアクセント
明度を落とした段に置き換える場所
- 本文・リンク
- ボタンの文字
- フォームのラベルと枠
- 注記・キャプション
そもそも色に意味を持たせない場所
- 必須・エラーの表示
- グラフの系列
3番目が見落とされがちです。色だけで情報を伝えている箇所は、コントラスト比を通しても WCAG 1.4.1(色の使用)に引っかかります。エラーを赤文字だけで示す、グラフの凡例を色だけで区別する、といった実装は、文字やアイコン、パターンを添えて直します。
/* 色だけに頼らないエラー表示 */
.field--error .field__input {
border-color: #9b2c17;
border-width: 2px;
}
.field__error {
display: flex;
align-items: flex-start;
gap: 6px;
color: #8a2612; /* #ffffff に対して約 6.3:1 */
font-size: .875rem;
font-weight: 700;
margin: 6px 0 0;
}
.field__error::before {
content: "!";
flex: 0 0 auto;
display: inline-grid;
place-items: center;
width: 1.25em;
height: 1.25em;
border-radius: 50%;
background: #8a2612;
color: #ffffff;
font-size: .75em;
line-height: 1;
}
記号を ::before で足しているので、HTML側に手を入れずに既存のエラー表示へ当てられます。スクリーンリーダーへの伝達は aria-describedby と aria-invalid で別に担保してください(装飾用の疑似要素は読み上げの保証がありません)。
案件の種類ごとに、どこまでやるか

「全部 AAA(7:1)で作る」は現実的ではないので、案件ごとに線を引きます。
| 案件の種類 | 判断 |
|---|---|
| 公共・自治体・教育 | AA 必須。入札・仕様書で要求されることが多く、Lighthouse のスコアを納品物に添える前提で組む |
| 医療・金融・保険 | AA 必須。加えてフォーム周りはフォーカス表示とエラー表示を手で確認する |
| 採用サイト | AA を満たす。幅広い年齢層が見るため、本文は 16px 以上・行間 1.8 前後を併せて確保する |
| コーポレート | AA を満たす。装飾文字・ロゴタイプは対象外として割り切る |
| ブランド・ファッション・アート | 本文とナビは AA。キービジュアル上の大きなコピーは 3:1 を下限として、表現を優先する判断を記録に残して進める |
| キャンペーンLP(短期) | ボタン・フォーム・価格表示は AA。装飾コピーは表現優先 |
最後の2つで大事なのは「割り切った」ことを言葉で残すことです。なぜその判断にしたかを記録しておかないと、公開後の指摘にその場で答えられません。「キービジュアルのコピーは装飾扱い、本文・導線はすべて AA 準拠」と1行書いておけば済みます。
採用サイトのように読み手の幅が広いものは、コントラストと同時に本文の組み方も効きます。実装の型そのものを確認したいときはこちら。
ブラウザ対応の確認のしかた
この記事のCSSで、対応状況を確認しておきたいのは次の3つです。
:focus-visible— 主要ブラウザで広く使えますが、古い環境を含める案件では:focusも併記します。.btn:focus { outline: 3px solid … }を先に書き、.btn:focus:not(:focus-visible) { outline: none; }で打ち消すと両対応になります。prefers-reduced-motion— 広く使えます。OS側の設定(macOS は「視差効果を減らす」、Windows は「アニメーションを表示する」をオフ)を切り替えて実機で確認してください。svh/clamp()—clamp()は広く使えます。svhは比較的新しい単位なので、対象ブラウザの下限を案件で決めているならmin-height: 60vh;を先に書いて上書きする形にします。
いずれも「使える/使えない」を記憶で判断せず、その案件のアクセス解析で上位にあるブラウザのバージョンを見てから決めるのが確実です。MDN の各ページと Can I use で現在の対応状況を確認し、確認した日付を案件のメモに残しておくと、半年後に同じ調べ直しをしなくて済みます。
コントラストと同時に見ておく3点

コントラスト比だけ通しても、読めない・操作できない画面は作れてしまいます。配色を直すときに一緒に確認する箇所を挙げます。
キーボード操作
Tab キーだけでページを一周して、いまどこにいるか常に分かるかを見ます。outline: none を書いてフォーカス表示を消している実装が残っていたら、そこが最優先の修正点です。フォーカスリングの色も対象で、WCAG 1.4.11 に照らすと周囲との比で 3:1 が要ります。淡い背景の上に淡いリングを置くと見えません。
ドロップダウンやモーダルを自作している場合は、Esc で閉じるか、閉じたあとフォーカスが元の要素に戻るかも確認します。
動きの抑制
prefers-reduced-motion は、ホバーのトランジションだけでなくスクロール連動のアニメーション、自動再生のカルーセル、パララックスまで対象です。配色を触るついでにまとめて入れておくのが効率的です。
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
transition-duration: .01ms !important;
scroll-behavior: auto !important;
}
}
0s ではなく .01ms にしているのは、animationend を待っている JavaScript が止まらないようにするためです。!important を使うのはこの用途に限定します。
表示速度への影響
配色の調整で速度を落としやすいのは次の3つです。
filter/backdrop-filter— 要素の重なりごとに合成が走ります。backdrop-filter: blur()を広い面積のヘッダーに常時かけると、スクロール中の再描画が目に見えて重くなる環境があります。使うなら面積を絞り、スクロールイベントでblurの値を動かさないこと。- 影の多重指定 —
box-shadowを要素ごとに3重4重に重ねると、ペイント回数が増えます。影で階層を作るのではなく、背景色の段差で作るほうが軽く、コントラストも管理しやすい。 - 大きな画像 — 色を調整するために画像を差し替えるとき、書き出しサイズを確認せずに置くと一気に重くなります。表示幅の2倍を上限に、WebP か AVIF で出します。
どれも「使うな」ではなく、面積と発生回数を抑えれば使えるという話です。DevTools の Performance パネルで記録を取り、Paint と Composite の時間を見てから判断してください。
グリッドで組んだ一覧ページなど、要素が多い画面ほど影とフィルターの影響が出やすくなります。レイアウト側の組み方はこちらで扱っています。
よくある質問

コントラスト比はどこまで上げればいいですか
本文は 4.5:1、24px以上の文字と UI の境界線は 3:1 が下限です。上げすぎて純黒(#000000)を純白(#ffffff)に載せると 21:1 になり、長文ではまぶしさで読みにくくなります。本文は 7:1 から 12:1 あたりに収めると、基準を超えつつ目にやさしい範囲になります。
ロゴやキャッチコピーも 4.5:1 を満たす必要がありますか
ロゴタイプは WCAG 1.4.3 の対象外です。純粋な装飾で、情報を伝えておらず、非表示にしても意味が変わらない文字も対象外になります。ただし「装飾だから」と判断した範囲は案件のメモに残してください。公開後に指摘が来たとき、その場で根拠を示せます。
淡いブランドカラーでは文字が置けないのでしょうか
置けない前提で設計を変えるのが正解です。淡い色はセクション背景や装飾の面に回し、文字には同じ色相で明度だけ落とした色を使います。色相と彩度を保てば、ブランドの印象は維持できます。色を変えるのではなく、使う場所を変える、という順番で考えてください。
DevTools の数値が出ないときはどうすればいいですか
背景が半透明、背景画像の上、グラデーションの上では DevTools が背景色を確定できないため数値が出ません。実際に表示されている画面をスクリーンショットで撮り、スポイトで文字部分と背景部分の色を拾って、コントラスト比の計算ツールに入れます。画像上の文字は明るい箇所・暗い箇所の両方で測ってください。
ダークモードも別に測り直す必要がありますか
必要です。ライトモードで通っていてもダークモードで落ちている実装は頻繁にあります。Chrome の DevTools の Rendering パネルで prefers-color-scheme: dark をエミュレートし、その状態で Lighthouse を再実行してください。切り替えボタンで実装している場合は、切り替えた後の状態で測ります。
まとめ
コントラスト比の確認は、3つの段に分けると実務で回ります。
設計時に段を作ってしまえば、実装中の判断がほぼ消えます。
淡いブランドカラーで基準に届かないとき、取れる手は「色を変える」ではありません。色を面に回し、文字は同じ色相の暗い段に置き換える。これで多くの案件は通ります。通らなければ、画像の上は帯を敷く、ボタンは文字色を反転させる、色だけで情報を伝えている箇所は記号を添える、と順に当てていきます。
公共・医療・金融・採用は AA を外さない。ブランド系とキャンペーンLPは、導線と本文を AA で固め、キービジュアル上のコピーは表現を優先してよい。ただしどこを割り切ったかを1行で残すこと。これだけ決めておけば、配色の相談に数字で答えられるようになります。



