Jak spełnić wymagania WCAG dotyczące kontrastu bez zgadywania

Co mierzy współczynnik kontrastu, jakie są progi AA i AAA dla tekstu i komponentów interfejsu oraz które błędy z szarością na bieli po cichu nie przechodzą za każdym razem.

Dla zwykłego tekstu treści poziom AA standardu WCAG wymaga współczynnika kontrastu wynoszącego co najmniej 4.5:1 wobec tła. Tekst duży potrzebuje 3:1. Komponenty interfejsu i grafika niosąca znaczenie potrzebują 3:1. Poziom AAA podnosi wymóg dla tekstu do 7:1, a dla tekstu dużego do 4.5:1. Współczynniki biegną od 1:1 (kolory identyczne) do 21:1 (czysta czerń na czystej bieli).

Nie da się tego ocenić okiem. Dwie pary, które na twoim monitorze wyglądają na podobnie czytelne, mogą leżeć po przeciwnych stronach progu, więc współczynnik trzeba policzyć.

Progi

Czego dotyczyAAAAA
Tekst zwykły4.5:17:1
Tekst duży3:14.5:1
Komponenty interfejsu i obiekty graficzne3:1brak wyższego progu

Biorą się one z trzech kryteriów sukcesu: 1.4.3 Kontrast (minimalny) na poziomie AA, 1.4.6 Kontrast (wzmocniony) na poziomie AAA oraz 1.4.11 Kontrast elementów nietekstowych na poziomie AA, które obejmuje wizualne granice kontrolek i te części grafiki, które są potrzebne do jej zrozumienia.

Tekst duży oznacza co najmniej 18 punktów albo 14 punktów w wersji pogrubionej, co wypada mniej więcej na 24px w zwykłej grubości albo około 18,5px w pogrubieniu. Nie oznacza to "nagłówka": nagłówek o rozmiarze 20px jest w rozumieniu przepisów tekstem zwykłym i potrzebuje pełnych 4.5:1.

Kilka rzeczy jest zwolnionych z wymogu: tekst czysto dekoracyjny, tekst w nieaktywnej kontrolce, tekst będący częścią obrazu zawierającego inne istotne treści wizualne oraz logotypy. Tekst zastępczy w polach i tekst pomocniczy zwolnione nie są.

Co ten współczynnik naprawdę mierzy

Wzór porównuje luminancję względną dwóch kolorów:

ratio = (L_lighter + 0.05) / (L_darker + 0.05)

Luminancja względna to liczba od 0 (czerń) do 1 (biel), która reprezentuje ilość światła emitowanego przez kolor. Oblicza się ją, odwracając krzywą gamma sRGB na każdym kanale, a następnie ważąc kanały:

L = 0.2126 R + 0.7152 G + 0.0722 B     (on linearised channels)

Wartość 0.05 dodana po obu stronach modeluje odrobinę światła otoczenia odbijającego się od ekranu i właśnie dlatego maksimum wynosi 21, a nie nieskończoność.

Wynikają z tego dwie rzeczy. Współczynnik zależy wyłącznie od luminancji, a nie od odcienia, więc dwa kolory mogą krańcowo różnić się odcieniem i mimo to być wobec siebie niemal niewidoczne. Jest też symetryczny, więc nie ma znaczenia, który kolor nazwiesz pierwszym planem.

Luminancja względna to nie jasność

Przyjrzyj się tym wagom. Zieleń wnosi około 72% luminancji, czerwień około 21%, a błękit ledwie 7%. To model ludzkiego widzenia, a nie tego, jak żywy wydaje się kolor, i daje wyniki, które wydają się błędne, dopóki się do nich nie przywyknie.

  • Czysta żółć #FFFF00 na bieli daje około 1.07:1, czyli jest prawie niewidoczna, mimo że żółć sprawia wrażenie mocnego koloru.
  • Ta sama żółć na czerni daje około 19.6:1, prawie tyle co biel na czerni.
  • Czysty błękit #0000FF na czerni daje około 2.4:1 i nie przechodzi żadnego progu, choć wygląda śmiało i jest mocno nasycony.

Z tego samego powodu jasność w modelu HSL jest kiepskim przybliżeniem. Dwa kolory mogą mieć w HSL jasność 50% i bardzo różną luminancję, ponieważ HSL traktuje odcień i jasność jako niezależne, a wzrok tak ich nie traktuje. Przelicz, a potem zmierz, zamiast zakładać, że krok jasności jest krokiem kontrastu.

Błędy, które powtarzają się bez końca

Szary tekst treści na bieli. To ten najczęstszy. Najjaśniejsza szarość, która przechodzi AA na bieli, to mniej więcej #767676, co daje 4.54:1. Jeden stopień jaśniej, #777777, to 4.48:1 i już nie przechodzi. Popularne "stonowane" szarości takie jak #999999 lądują w okolicach 2.9:1, czyli poniżej dwóch trzecich wymogu. Jeśli chcesz AAA na bieli, potrzebujesz mniej więcej #595959, co daje dokładnie 7:1.

Tekst zastępczy w polach i tekst pomocniczy. Ustawia się je o kilka odcieni jaśniej niż tekst treści, bo są drugoplanowe. Wciąż są tekstem i wciąż potrzebują 4.5:1.

Kolory półprzezroczyste. Współczynnik policzony z zadeklarowanego koloru jest bez znaczenia, jeśli element ma krycie 60%. Wylicz kolor złożony, który faktycznie pojawia się na ekranie, i zmierz właśnie jego.

Tekst na zdjęciach, gradientach i wideo. Współczynnik zmienia się piksel po pikselu, a liczy się ten najgorszy piksel. Zwykłym rozwiązaniem jest przyciemniająca warstwa pod tekstem, a nie liczenie na to, że zdjęcie pozostanie ciemne.

Przyciski w kolorze marki. Biały tekst na kolorze marki o średnim tonie bardzo często ląduje między 3:1 a 4.5:1, przechodząc jako obiekt graficzny i nie przechodząc jako etykieta. Przyciemnij przycisk albo świadomie przyjmij niezgodność.

Wskaźniki fokusu i przyciski złożone z samej ikony. Jedne i drugie podlegają regule 3:1 dla elementów nietekstowych. Obramowanie fokusu w nieco innym odcieniu tego samego koloru to częste przeoczenie, podobnie jak szara ikona będąca jedyną treścią przycisku.

Tryb ciemny przez odwrócenie. Odwrócenie jasnej palety nie zachowuje współczynników, ponieważ luminancja nie jest symetryczna wobec środka. Czysta biel na czystej czerni daje maksymalne 21:1, ale wielu ludzi odczuwa wtedy nieprzyjemną poświatę, więc częstym kompromisem jest złamana biel na bardzo ciemnej szarości, na przykład #E6E6E6 na #121212, co daje mniej więcej 15:1.

Mierzenie ze zrzutu ekranu. Kroplomierz na krawędzi wygładzonego tekstu pobiera mieszankę tekstu i tła, a nie kolor tekstu. Pobieraj próbkę ze środka grubej kreski albo, lepiej, odczytaj wartości ze swojego CSS.

Sposób pracy, który omija zgadywanie

Najpierw ustal tło, potem przyciemniaj albo rozjaśniaj pierwszy plan, aż przekroczy próg z niewielkim zapasem, i zapisz tę parę. Buduj paletę z zatwierdzonych par, a nie z zatwierdzonych kolorów: kolor nie jest dostępny sam z siebie, tylko w zestawieniu. Sprawdzaj też każdy stan, a nie tylko spoczynkowy, oraz oba motywy, jeśli wydajesz tryb ciemny.

Jeszcze jedna uwaga. Nowszy model percepcyjny, APCA, jest rozwijany z myślą o przyszłej wersji WCAG i zachowuje się dość odmiennie, zwłaszcza dla jasnego tekstu na ciemnym tle. Warto o nim wiedzieć, ale liczbami, do których trzeba się dziś stosować, są powyższe współczynniki z WCAG 2.