背景色に最適な文字色を1行数式で自動判定!
UIを開発していると、こんな場面に出くわしたことはないでしょうか。
「このバッジの背景色、黄色にしたら文字が見えなくなった...」
「ユーザーが自由に色を選べるカラータグ、文字色はどうすれば?」
背景色が動的に変わるUI要素では、文字色を白にするか黒にするかの判断が常につきまといます。手動で1色ずつ設定するのは現実的ではありません。
実は、たった1行の数式でこの問題を解決できます。
背景色と文字色の見やすさが重要な理由
視認性がユーザー体験を左右する
Webサイトやアプリケーションにおいて、テキストの読みやすさはユーザー体験の根幹です。背景色と文字色のコントラストが不十分だと、以下のような問題が発生します。
- 読み飛ばし: ユーザーが重要な情報を見落とす
- 離脱率の上昇: 読みにくいサイトからはすぐに離れる
- アクセシビリティの欠如: 色覚多様性を持つユーザーや高齢者にとって致命的
動的な背景色で問題は深刻化する
固定デザインであれば、デザイナーが1つずつ文字色を調整できます。しかし、以下のようなケースでは背景色が動的に変わるため、手動調整は不可能です。
- カテゴリタグ・バッジ: ユーザーやシステムが色を自由に設定する
- カラーテーマ: ダークモード/ライトモードの切り替え
- データ可視化: ヒートマップやグラフの色分け
- 管理画面: 会議タイプ、ステータス、優先度ラベルなど
こうした場面で必要なのは、背景色を入力として、最適な文字色を自動的に返す仕組みです。
NTSC輝度係数を使った自動判定の仕組み
1行の数式で解決する
背景色から文字色を自動判定する数式は、驚くほどシンプルです。
luminance = (0.299 × R + 0.587 × G + 0.114 × B) / 255
この計算結果(0〜1の範囲)が 0.5を超えれば明るい背景 → 黒い文字、0.5以下なら暗い背景 → 白い文字を選択します。
なぜ「0.299, 0.587, 0.114」なのか?
この3つの数値はNTSC加重係数と呼ばれ、1953年にアメリカのNTSCカラーテレビ規格で定義されました。後にITU-R BT.601として国際標準化されています。
単純にRGBを平均((R+G+B)/3)するのではなく、人間の目の感度に基づいて重み付けしています。
| 色 | 係数 | 理由 |
|---|---|---|
| 赤(R) | 0.299(29.9%) | 中程度の感度 |
| 緑(G) | 0.587(58.7%) | 最も敏感。同じ数値でも緑は明るく感じる |
| 青(B) | 0.114(11.4%) | 最も鈍感。青は暗く感じやすい |
例えば、純粋な緑 rgb(0, 255, 0) と純粋な青 rgb(0, 0, 255) はどちらもRGB値の1つが255ですが、人間の目には緑の方がはるかに明るく見えます。単純平均ではどちらも同じ85になってしまいますが、この加重平均なら緑=149.7、青=29.1と正しく差を反映できます。
実際の判定例
| 背景色 | HEX | R,G,B | 輝度 | 判定 |
|---|---|---|---|---|
| 赤 | #ef4444 | 239, 68, 68 | 0.43 | 白文字 |
| 黄色 | #f59e0b | 245, 158, 11 | 0.67 | 黒文字 |
| 青 | #3b82f6 | 59, 130, 246 | 0.44 | 白文字 |
| 緑 | #10b981 | 16, 185, 129 | 0.52 | 黒文字 |
| 紫 | #8b5cf6 | 139, 92, 246 | 0.44 | 白文字 |
| グレー | #6b7280 | 107, 114, 128 | 0.44 | 白文字 |
実際の導入方法とメリット
JavaScript / TypeScript での実装
最もよく使われるWeb実装です。HEXカラーコードを引数に取り、白か黒を返します。
function getContrastTextColor(hexColor: string): string {
const hex = hexColor.replace('#', '');
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
return luminance > 0.5 ? '#1e293b' : '#ffffff';
}
使い方はシンプルです。
// バッジのスタイルに適用
const badgeStyle = {
backgroundColor: userColor,
color: getContrastTextColor(userColor),
};
Python での実装
バックエンドやデータ処理でも同じロジックが使えます。
def get_contrast_text_color(hex_color: str) -> str:
hex_color = hex_color.lstrip('#')
r = int(hex_color[0:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:6], 16)
luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
return '#1e293b' if luminance > 0.5 else '#ffffff'
CSS(カスタムプロパティ)での応用
CSS単体では動的計算が難しいですが、CSS変数とJavaScriptを組み合わせることで実現できます。
.badge {
--bg-color: #ef4444;
background-color: var(--bg-color);
/* JavaScriptで動的に設定 */
color: var(--text-color, #ffffff);
}
const badge = document.querySelector('.badge');
const bgColor = getComputedStyle(badge).getPropertyValue('--bg-color').trim();
badge.style.setProperty('--text-color', getContrastTextColor(bgColor));
利用シーンの具体例
この自動判定は以下のような場面で威力を発揮します。
- タグ・バッジ: カテゴリラベル、ステータス表示、優先度マーク
- カレンダー: イベントの色分け表示
- ダッシュボード: KPIカードの背景色に応じた数値表示
- チャート: グラフ上のデータラベル
- 管理画面: ユーザーがカスタマイズ可能な色設定
BT.601 vs BT.709 vs WCAG
同じ目的で使われる規格が複数存在します。用途に応じて使い分けましょう。
| 規格 | 係数(R, G, B) | 用途 |
|---|---|---|
| BT.601(NTSC) | 0.299, 0.587, 0.114 | SD映像、一般的なWeb実装 |
| BT.709 | 0.2126, 0.7152, 0.0722 | HD映像、より正確な色再現 |
| WCAG 2.0 | sRGBガンマ補正後にBT.709 | アクセシビリティ準拠 |
一般的なUI開発ではBT.601で十分です。WCAG準拠が求められる場合は、ガンマ補正を含むより厳密な計算が必要になります。
WCAG準拠にするなら
WCAGでは、コントラスト比を以下の式で計算します。
コントラスト比 = (L1 + 0.05) / (L2 + 0.05)
L1は明るい方、L2は暗い方の相対輝度です。通常テキストでは4.5:1以上(AA基準)、大きなテキストでは3:1以上が求められます。
厳密なアクセシビリティ対応が必要な場合は、BT.601の簡易計算ではなく、sRGBガンマ補正を含むWCAGの計算式を使いましょう。
まとめ
- NTSC輝度係数
(0.299, 0.587, 0.114)を使えば、背景色から最適な文字色を1行で自動判定できる - この係数は1953年のカラーテレビ規格に由来し、人間の目の感度を反映している
- JavaScript、Python、CSSなどどの言語でも数行で実装可能
- より厳密なアクセシビリティ対応にはWCAGのコントラスト比計算を検討する
動的に色が変わるUI要素を扱う開発者にとって、この数式は知っておいて損のないテクニックです。たった1行で、デザインの品質とユーザー体験を確実に向上させることができます。
AIコーディングツールへの指示例
Claude CodeやGitHub Copilotなどのコーディングアシスタントに、この機能を実装させたい場合の指示例を紹介します。自分でコードを書かなくても、適切に指示すれば数秒で実装が完了します。
基本的な指示:
「背景色のHEXコードを受け取り、NTSC輝度係数(BT.601: 0.299, 0.587, 0.114)を使って文字色を白か黒か自動判定する関数を作って」
既存コードへの適用:
「このバッジコンポーネントの文字色を、背景色のluminanceから自動判定するようにして。BT.601の加重係数を使って、明るい背景なら暗い文字、暗い背景なら白文字にして」
より具体的な指示(プロジェクト全体への適用):
「プロジェクト内でユーザーが色を選択できるUI要素(タグ、バッジ、カテゴリラベル等)を全て洗い出して、文字色をNTSC輝度係数で自動判定するように統一して。共通ユーティリティ関数として切り出すこと」
WCAG準拠を求める場合:
「背景色と文字色のコントラスト比がWCAG 2.0のAA基準(4.5:1以上)を満たすように、文字色を自動選択する関数を実装して。sRGBガンマ補正を含むWCAGの相対輝度計算を使うこと」
ポイントは、「NTSC輝度係数」「BT.601」「0.299, 0.587, 0.114」 といったキーワードを指示に含めることです。AIはこれらの用語から正確な数式と実装パターンを認識し、適切なコードを生成します。逆に「背景色に合わせて文字色を変えて」だけだと、単純なif文や不正確な計算式が生成される可能性があります。