Color Contrast Checker
Проверяйте контрастность цветов переднего плана и фона по стандартам WCAG AA и AAA
Цвет переднего плана (текст)
Цвет фона
Крупный текст (18px жирный)
Обычный текст — так будет выглядеть основной текст на выбранном вами фоне.
Коэффициент контрастности
14.63:1
Соответствие WCAG
Пройдено
Обычный AA
Пройдено
Обычный AAA
Пройдено
Крупный AA
Пройдено
Крупный AAA
WCAG AA — Обычный текст: 4.5:1, Крупный текст (18px+ или 14px жирный): 3:1
WCAG AAA — Обычный текст: 7:1, Крупный текст (18px+ или 14px жирный): 4.5:1
Что такое проверка контрастности цветов?
Проверка контрастности цветов измеряет разницу в яркости между цветом переднего плана (как правило, текстом) и цветом фона, выражая результат в виде соотношения. Соотношение 1:1 означает, что цвета идентичны; максимальное значение — 21:1, соответствующее чёрному тексту на белом фоне или наоборот. Руководство по обеспечению доступности веб-контента (WCAG), опубликованное консорциумом W3C, определяет минимальные коэффициенты контрастности, которым должен соответствовать текст, чтобы люди со слабым зрением или нарушениями цветовосприятия могли его читать.
Формула расчёта контрастности взята из WCAG 2.x и основана на относительной яркости — показателе того, насколько ярким воспринимается цвет человеческим глазом. Относительная яркость рассчитывается путём линеаризации каждого канала sRGB (удаления гаммы) и взвешивания каналов по коэффициентам ITU-R BT.709: 0,2126 для красного, 0,7152 для зелёного и 0,0722 для синего. Зелёный вносит наибольший вклад, поскольку человеческий глаз наиболее чувствителен к зелёному свету. Само соотношение вычисляется по формуле (L1 + 0,05) / (L2 + 0,05), где L1 — яркость более светлого цвета.
WCAG определяет два уровня соответствия. Уровень AA требует коэффициента контрастности не менее 4,5:1 для обычного текста и 3:1 для крупного (18px и выше или 14px жирным). Уровень AAA повышает порог до 7:1 и 4,5:1 соответственно. WCAG 2.1 также ввёл критерий успеха 1.4.11, требующий соотношения 3:1 для нетекстовых элементов интерфейса: рамок, иконок и индикаторов фокуса.
Зачем использовать этот инструмент?
Визуальная оценка контрастности ненадёжна. Цвета, которые кажутся различимыми на откалиброванном мониторе, могут сливаться на экране бюджетного ноутбука, под прямыми солнечными лучами или у людей с дейтеранопией. Числовое соотношение устраняет неопределённость и даёт однозначный ответ о соответствии стандарту WCAG.
Сценарии использования
Требования WCAG к коэффициенту контрастности
Таблица ниже содержит минимальные коэффициенты контрастности, требуемые WCAG 2.1 для различных типов контента и уровней соответствия. Крупным считается текст размером 18px (24 CSS-пикселя) и выше при обычном начертании, или 14px (18,66 CSS-пикселя) и выше при жирном начертании.
| Уровень | Мин. соотношение | Применяется к | Примечание |
|---|---|---|---|
| AA Normal text | 4.5 : 1 | Body text, paragraphs, labels | Minimum for most UI text |
| AA Large text | 3.0 : 1 | Text >= 18px, or >= 14px bold | Minimum for headings |
| AA UI components | 3.0 : 1 | Borders, icons, focus indicators | Non-text contrast (WCAG 1.4.11) |
| AAA Normal text | 7.0 : 1 | Body text at highest standard | Enhanced readability |
| AAA Large text | 4.5 : 1 | Large text at highest standard | Enhanced for headings |
Яркость, AA и AAA: пояснение
Расчёт коэффициента контрастности состоит из трёх этапов: вычисление яркости каждого цвета, получение соотношения и сравнение его с порогами WCAG.
Примеры кода
Расчёт коэффициентов контрастности WCAG программным способом. В каждом примере реализованы формула относительной яркости из WCAG 2.x и расчёт коэффициента контрастности. Для сравнения протестированы одинаковые пары: чёрный на белом и индиго на белом.
// Calculate relative luminance per WCAG 2.x (sRGB)
function luminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c /= 255
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
})
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs
}
// Contrast ratio between two RGB colors
function contrastRatio(fg, bg) {
const l1 = luminance(...fg)
const l2 = luminance(...bg)
const lighter = Math.max(l1, l2)
const darker = Math.min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
contrastRatio([0, 0, 0], [255, 255, 255]) // -> 21.0
contrastRatio([99, 102, 241], [255, 255, 255]) // -> 3.95
contrastRatio([29, 78, 216], [255, 255, 255]) // -> 6.06 (AA pass)def luminance(r: int, g: int, b: int) -> float:
"""Relative luminance per WCAG 2.x, ITU-R BT.709 coefficients."""
channels = []
for c in (r, g, b):
c /= 255
channels.append(c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4)
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]
def contrast_ratio(fg: tuple, bg: tuple) -> float:
l1 = luminance(*fg)
l2 = luminance(*bg)
lighter, darker = max(l1, l2), min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
print(f"{contrast_ratio((0, 0, 0), (255, 255, 255)):.2f}") # -> 21.00
print(f"{contrast_ratio((99, 102, 241), (255, 255, 255)):.2f}") # -> 3.95
# Check WCAG AA for normal text
ratio = contrast_ratio((29, 78, 216), (255, 255, 255))
print(f"{ratio:.2f} — {'AA pass' if ratio >= 4.5 else 'AA fail'}") # -> 6.06 — AA passpackage main
import (
"fmt"
"math"
)
func linearize(c float64) float64 {
c /= 255
if c <= 0.04045 {
return c / 12.92
}
return math.Pow((c+0.055)/1.055, 2.4)
}
func luminance(r, g, b int) float64 {
return 0.2126*linearize(float64(r)) +
0.7152*linearize(float64(g)) +
0.0722*linearize(float64(b))
}
func contrastRatio(fgR, fgG, fgB, bgR, bgG, bgB int) float64 {
l1 := luminance(fgR, fgG, fgB)
l2 := luminance(bgR, bgG, bgB)
lighter := math.Max(l1, l2)
darker := math.Min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
func main() {
ratio := contrastRatio(0, 0, 0, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 21.00
ratio = contrastRatio(29, 78, 216, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 6.06 (AA pass for normal text)
}/* WCAG-safe color pairs — tested contrast ratios */
/* 12.63:1 — passes AAA normal text */
.high-contrast {
color: #1e293b; /* slate-800 */
background: #f8fafc; /* slate-50 */
}
/* 7.07:1 — passes AAA normal text */
.dark-theme-text {
color: #e2e8f0; /* slate-200 */
background: #0f172a; /* slate-900 */
}
/* 4.57:1 — passes AA normal, fails AAA */
.accent-on-white {
color: #1d4ed8; /* blue-700 */
background: #ffffff;
}
/* 2.14:1 — fails AA for text, but passes 3:1 for large text */
.muted-heading {
color: #94a3b8; /* slate-400 */
background: #ffffff;
}