Коефіцієнт контрасту
наскільки два кольори різні, виражено числом
Що це таке
Коефіцієнт контрасту — це одне число від 1:1 до 21:1, за яким WCAG визначає, чи достатньо текст, іконки та інші видимі частини сторінки вирізняються на тлі, де вони стоять. Він порівнює відносну яскравість (relative luminance) двох кольорів, тобто їхню світлість, і зовсім не зважає на відтінок. Дизайнери кажуть також «колірний контраст» або «контраст яскравості», в англомовних звітах аудиту для кожної пари кольорів пишуть contrast ratio, і все це — те саме обчислення.
Формула коротка. Візьміть відносну яскравість світлішого кольору, L1, і темнішого, L2, та поділіть (L1 + 0,05) на (L2 + 0,05). Відносну яскравість нормовано від 0 для найтемнішого чорного до 1 для найсвітлішого білого. Для кольору sRGB кожен канал спершу переводять із гамма-кодованого значення в лінійне світло, а потім три канали зважують: 0,2126 для червоного, 0,7152 для зеленого і 0,0722 для синього. Два однакові кольори дають 1:1, чорне на білому — 21:1.
Саме ці ваги обманюють око. Чистий зелений на чорному дає близько 15,3:1, а чистий синій на
чорному — лише приблизно 2,4:1, хоча обидва здаються однаково яскравими. Чистий червоний на білому
дає 3,998:1. Середньо-сірий #767676 на білому має 4,54:1, а #777777, на крок світліший, —
4,48:1. Усе обчислення вміщується в десяток рядків:
// Коефіцієнт контрасту двох кольорів sRGB за визначенням WCAG 2.2
const linear = (c) => {
const s = c / 255;
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
};
const luminance = (rgb) => {
const [r, g, b] = rgb.map(linear);
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
};
const contrast = (a, b) => {
const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
return (hi + 0.05) / (lo + 0.05);
};
contrast([118, 118, 118], [255, 255, 255]); // 4.54...
У WCAG 2.2 коефіцієнт є визначенням, а чотири критерії успіху встановлюють для нього пороги:
- 1.4.3 Contrast (Minimum), рівень AA: щонайменше 4,5:1 для тексту й зображень тексту і щонайменше 3:1 для великого тексту. Текст у неактивному елементі керування, чиста декорація та логотипи звільнені від вимоги.
- 1.4.6 Contrast (Enhanced), рівень AAA: щонайменше 7:1, а для великого тексту 4,5:1.
- 1.4.11 Non-text Contrast, рівень AA: щонайменше 3:1 відносно суміжних кольорів для всього, що позначає елемент керування та його стан, і для тих частин графіки, без яких її не зрозуміти.
- 2.4.13 Focus Appearance, рівень AAA: ділянка індикатора фокуса, не менша за периметр елемента завтовшки 2 CSS-пікселі, змінюється щонайменше на 3:1 між станом із фокусом і без нього.
Великий текст — це щонайменше 18 пунктів або 14 пунктів жирним. У CSS-пікселях це 24px або близько 18,7px для жирного накреслення.
Чому це важливо
Пороги виведено з виміряної втрати зору, і знати їхнє походження корисно, коли хтось пропонує їх послабити. Документ Understanding до WCAG бере за відправну точку 3:1 — мінімум, який стандарт ANSI встановив для людей із типовим зором. Зір 20/40 знижує контрастну чутливість приблизно в 1,5 раза, тож 3 × 1,5 дає 4,5:1, а той самий документ зазначає, що 20/40 зазвичай називають типовою гостротою зору приблизно у 80 років. Поріг AAA 7:1 компенсує зір близько 20/80. Оскільки коефіцієнт враховує лише яскравість, він працює для більшості порушень колірного зору, де правило на основі відтінку схибило б. Той самий запас допомагає кожному, хто читає з телефона на яскравому сонці.
Отже, коефіцієнт контрасту вирішує, які кольори бренду можна брати для якої роботи, і ухвалити це рішення в палітрі значно дешевше, ніж на готовій сторінці. Брендовий колір із коефіцієнтом 3,2:1 на білому все одно має застосування: великі заголовки, іконки й рамка поля форми, яким досить 3:1, тло під темним текстом, декорація, сам логотип. Основний текст, посилання в абзаці й текст-заповнювач у полі потребують 4,5:1, тож їх цей колір залишає іншим. Вирішити це один раз у дизайн-токенах займає пів дня. Виявити це після запуску означає перефарбувати кожен компонент, що позичив цей колір, а темна тема подвоює кількість пар для перевірки.
Контраст — також одна з небагатьох вимог WCAG, яку машина може перевірити точно, якщо знає обидва кольори. Тому він першим з’являється в більшості автоматичних аудитів і першим питанням у багатьох закупівельних чеклистах, а рівень AA — той, на який найчастіше посилаються правила доступності й договори. Прагнути 7:1 рівня AAA всюди — вибір, який варто зважити: сама WCAG не радить вимагати AAA як політику для цілих сайтів, проте 7:1 — слушна мета для довгого тексту, де палітра це дозволяє.
Як це виглядає на практиці
Дві сторінки цього сайту показують коефіцієнт як записане число, а не оцінку на око.
Коли систему кольорів сайту закрили, кожен із 28 кольорів отримав виміряний коефіцієнт контрасту саме для того тла, на якому його вжито, а одинадцять брендових значень існують в одному місці, у токенах. Лінтер розрізняє п’ять видів помилок, і один із них — записаний коефіцієнт, що не збігається з дійсним. Постійне правило системи, крім іншого, не дозволяє поступатися зафіксованим коефіцієнтом заради дизайну, а охочий додати ще один колір понад ці 28 мусить, доводячи потребу в ньому, назвати і його коефіцієнт. Та сама сторінка вводить ще один поріг: якщо відстань між двома кольорами в перцептивно рівномірному колірному просторі не сягає 0,02, їх вважають одним кольором у двох записах. Це число розрізняє позиції палітри і є іншою мірою, ніж контраст.
Найважчим випадком був текст поверх фотографії. Сторінка про те, як увесь сайт підтягнули до WCAG 2.2 рівня AA, пояснює, що автоматичний рушій правил позначає такий контраст як недоступний для своєї оцінки, а сайт доти покладався на міркування, а не на вимір. Коли ж виміряли, у 49 із 64 поєднань сторінки та теми контраст не дотягував до AA, і винними були дві поверхні, яких у дизайні ніхто не вважав своїми. Перевірку, яка їх виявила, відтоді перетворено на обов’язковий мінімум: кожна пара повинна давати AA на тлі стіни, згенерованої під час збирання, і досить однієї пари нижче порога, щоб збирання впало.
Де виникають проблеми
Текст поверх фотографії проходить в інструменті й провалюється на екрані. WCAG вимірює текст відносно заданого тла і вважає тло білим, якщо його не вказано. Заголовок на hero-зображенні має оголошений колір тла, але під літерами лежить зовсім інший, тож перевірка або вимірює хибну пару, або повертає елемент на ручний розгляд. Вимірюйте відносно найсвітліших і найтемніших пікселів, на яких може опинитися текст, за кожного кадрування й ширини, або підкладіть під текст суцільну плашку чи темну вуаль, щоб колір під ним був відомий.
Токен має 4,6:1, а сторінка показує 3,9:1. Прозорість, текст у rgba(), напівпрозоре
накладання або режим змішування змінюють колір, який доходить до екрана, тож коефіцієнт, записаний
для токена, описує колір, якого ніхто не бачить. Обчислюйте коефіцієнт для пари, яку справді видно
після накладання шарів, або взагалі тримайте альфа-канал подалі від тексту.
Аудит показує 4,49:1 як пройдений. Коефіцієнт з одним знаком після коми перетворює 4,49 на 4,5. Документ Understanding прямо каже, що значення не округлюють: 4,499:1 не досягає порогу 4,5:1. Зберігайте щонайменше два знаки після коми й порівнюйте з порогом сире значення.
Світлу тему перевірено, а темна йде в продакшн на довірі. Кожна тема й кожен стан, якого може набути колір, — окрема пара: hover, фокус, відвідане посилання, помилка і текст-заповнювач, який вважається текстом і потребує 4,5:1. Вимкнений елемент керування звільнений від вимоги. Генеруйте список пар із токенів, для кожної теми й кожного стану, і перевіряйте список, а не знімок екрана.
Тонкий шрифт проходить на папері й блякне на екрані. Коефіцієнт обчислюють із заданих кольорів, але згладжування малює волосяні накреслення блідіше, ніж їхній колір у CSS, і документ Understanding називає саме цей випадок: такий текст може номінально пройти й водночас читатися зі значно нижчим контрастом. Підвищуйте коефіцієнт для світлих накреслень або оберіть важче накреслення гарнітури.
Що почитати далі
- WCAG 2.2: визначення contrast ratio — нормативне визначення з примітками про колір тла, білий як типовий фон і згладжування.
- Understanding SC 1.4.3 Contrast (Minimum) — звідки взялися 4,5:1 і 3:1, як визначають великий текст і чому коефіцієнти не округлюють.
- Understanding SC 1.4.11 Non-text Contrast — правило 3:1 для елементів керування, їхніх станів і змістовної графіки, з прикладами.
- Understanding SC 1.4.6 Contrast (Enhanced) — рівень AAA з порогом 7:1 і читачі, для яких він призначений.
- CSS Color Module Level 4 — передавальна функція sRGB і колірні простори, на які спирається формула яскравості.