背景色に応じて文字色を白にするか黒にするか。デザインシステムを作っていると、この組み合わせ表を何度も更新した経験があるはずです。ブランドカラーが増え、ユーザーがテーマ色を選べるようになると、組み合わせはすぐに破綻します。
CSSの`contrast-color()`は、渡した色に対してコントラストが最大になる白または黒を返す関数です。Chrome 147、Firefox 146、Safari 26で対応し、Baseline 2026になりました。この記事では、`contrast-color()`で何が変わるのか、使いどころ、そして「白か黒しか返さない」という制約を整理します。
30秒でわかる結論
- `contrast-color()`は、背景色から白または黒を自動で選ぶCSS関数。
- Chrome 147 / Firefox 146 / Safari 26で対応し、Baseline 2026。
- 動的なブランドカラー、バッジ、ユーザーテーマの文字色に使える。
- 返るのは白か黒のみ。中間色ではWCAG AAを満たせない場合がある。
- 動的に色が変わる箇所から使い、静的なデザインは従来のコントラスト設計を維持する。
何が起きたのか:Baseline 2026入り
`contrast-color()`はCSS Color 5で定義された関数で、引数の色に対して白と黒のどちらがコントラストが高いかを計算して返します。同率の場合は白を返します。Chrome 147、Firefox 146、Safari 26が出揃ったことで、主要ブラウザで使える状態になりました。
これまで動的な背景色に対しては、JSで輝度を計算する、デザイントークンごとに文字色を用意する、あるいは「明るい色には黒、暗い色には白」というルールを人手で運用する必要がありました。`contrast-color()`はその判断をブラウザに委ねます。
何が変わるのか:背景と文字色のペア管理が不要になる
最も分かりやすいのは、ボタンやバッジの文字色です。背景色がブランドカラーやユーザー選択色で変わっても、`color: contrast-color(var(--bg))`と書けば、白か黒を自動で選びます。
:root {
--brand: #3b5ba9;
}
.button {
background: var(--brand);
color: contrast-color(var(--brand));
}
.badge {
background: var(--badge-bg, #c2410c);
color: contrast-color(var(--badge-bg, #c2410c));
}これまで必要だった「背景色ごとの文字色表」が不要になり、新しいブランドカラーを追加したときの更新漏れも減ります。たとえばユーザーがプロフィール背景を16色から選ぶ画面では、`contrast-color()`を入れるだけで16パターン分の文字色を用意せずに済みます。
場面 | これまで | contrast-color()後 |
|---|---|---|
ブランドカラーのボタン | 白/黒を手動で決定 | 背景から自動選択 |
ユーザー選択テーマ | JSで輝度計算 | CSSだけで完結 |
ステータスバッジ | 色ごとに文字色を定義 | 背景色から自動選択 |
ダークモード | メディアクエリで分岐 | `light-dark()`と組み合わせ |
使い方:ボタンとバッジ
基本は`background`に色を指定し、`color`に`contrast-color()`を渡すだけです。CSS変数と組み合わせると、テーマ切り替えにも追随します。
:root {
--button-bg: lightblue;
}
button {
background-color: var(--button-bg);
color: contrast-color(var(--button-bg));
}
/* ユーザーが色を選ぶUI */
.theme-preview {
background: var(--preview-color);
color: contrast-color(var(--preview-color));
}ダークモードと組み合わせるなら、`color-scheme: light dark`を宣言し、`light-dark()`で背景色を切り替えます。文字色は`contrast-color()`に任せると、テーマごとのペア管理が減ります。
制約:白か黒しか返さない
`contrast-color()`が返すのは、白または黒だけです。そのため、中間色の背景ではどちらも十分なコントラストにならない場合があります。MDNは、ロイヤルブルー(`#2277d3`)の背景に対して黒文字が返り、小さい文字では読みにくくなる例を挙げています。
じゃあ使えないの?→ そんなことはありません。明るい色か暗い色に限定したブランドカラーなら効果的です。中間色を多用するデザインでは、従来のコントラスト設計や`color-mix()`で文字色を調整する併用が必要です。
また、`contrast-color()`はWCAG AAを保証するものではありません。ブラウザのアルゴリズムに依存するため、重要なテキストでは実際のコントラスト比を確認してください。
実務での使い方:動的な色から始める
- ユーザーが選ぶテーマカラー、プロフィールの背景色、タグの色。
- ブランドカラーが増える管理画面のボタン・バッジ。
- ステータス(成功・警告・エラー)の背景色に対する文字色。
- ダークモードとライトモードで同じトークンから文字色を導く。
一方で、静的なデザインカンプの文字色をすべて`contrast-color()`に置き換える必要はありません。デザイナーが選んだ色を再現したい場合は、従来どおり明示的な色指定を優先します。
まずは「ユーザーが色を選べる画面」1つで試します。背景色のバリエーションを10個ほど用意し、白/黒の切り替わりとコントラスト比を確認すると、自社のブランドカラーで使えるか判断できます。
フォールバック:`@supports`で安全に
古いブラウザでは`contrast-color()`が無効になり、`color`の宣言全体が無効になる可能性があります。外側に従来の文字色を書き、対応ブラウザだけ上書きします。
.button {
background: var(--brand);
color: #fff; /* フォールバック */
}
@supports (color: contrast-color(red)) {
.button {
color: contrast-color(var(--brand));
}
}`@supports`の条件は、実際に使う値の形で書くのがポイントです。`contrast-color(red)`が通ることを確認してから、変数版を有効にします。
注意点:アクセシビリティは自動保証ではない
- 白/黒しか返さないため、中間色ではAAを満たせない場合がある。
- ブラウザごとにアルゴリズムが異なる可能性がある。
- 小さい文字、細いフォント、透過背景では特に確認が必要。
- `@supports`フォールバックを用意する。
- 重要なUIでは、自動計算だけでなく実際のコントラスト比を測る。
アクセシビリティ検査は、`contrast-color()`を入れた後にも行います。自動で白/黒を選ぶことと、WCAGを満たすことは別の話です。特に中間色のブランドカラーは、手動での調整余地を残してください。
対応状況と使う判断
ブラウザ | 対応 | 備考 |
|---|---|---|
Chrome / Edge 147以降 | 対応 | Baseline 2026 |
Firefox 146以降 | 対応 | Baseline 2026 |
Safari 26以降 | 対応 | Baseline 2026 |
自分なら使うか:今すぐ使う。 ただし、すべての文字色を置き換えるのではなく、動的に色が変わるバッジ、ユーザーテーマ、管理画面のボタンなど、効果が明確な箇所に限定します。中間色では従来のコントラスト設計を併用します。
まとめ
- `contrast-color()`は背景色から白または黒を自動で選ぶ。
- Chrome 147 / Firefox 146 / Safari 26で対応し、Baseline 2026。
- 動的なブランドカラーやユーザーテーマの文字色管理が楽になる。
- 白/黒のみで、中間色ではAAを満たせない場合がある。
- 動的な色の箇所から導入し、`@supports`と手動のコントラスト確認を併用する。






