Jasne i ciemne palety: kontrola kontrastu i ograniczenia

Management Summary
Kontrast to widoczna różnica między elementem strony a tłem. W jasnym i ciemnym motywie pomaga rozpoznawać tekst, przyciski i zaznaczenia. Sama kompletna paleta barw tego nie zapewnia: znaczenie mają faktyczne pary kolorów, wielkość tekstu, przezroczystość i stan elementu. Dlatego ten sam projekt może być czytelny w jednym widoku, a trudny w drugim. Obliczenia kolorów są pomocną wskazówką, lecz praktyczny wynik zależy od wyświetlanej strony i sposobu jej obsługi.
Spis treści
Jasny i ciemny motyw mogą używać tych samych nazw zmiennych CSS z różnymi wartościami barw. Czytelność zależy jednak od faktycznie wyświetlanej pary pierwszego planu i tła. Paleta dostarcza możliwych barw, a zastosowanie na stronie określa potrzebne kontrole kontrastu.

Który próg obowiązuje?
WCAG 2.2 wymaga na poziomie AA zasadniczo co najmniej 4,5:1 dla zwykłego tekstu. Dla dużego tekstu wystarcza 3:1: chodzi o co najmniej 18 punktów, czyli 24 piksele CSS, albo 14 punktów pogrubionych, czyli około 18,67 piksela CSS. Poziom AAA wymaga 7:1 dla tekstu zwykłego i 4,5:1 dla dużego. Wyjątki obejmują między innymi logotypy, tekst czysto dekoracyjny i tekst w nieaktywnych elementach sterujących.
Informacje wizualne potrzebne do rozpoznania elementów sterujących, stanów lub znaczących grafik podlegają również kryterium nietekstowego kontrastu 1.4.11. Próg wynosi 3:1 wobec sąsiednich barw, z wyjątkami określonymi w kryterium. Nie każda pojedyncza ramka musi osiągać ten kontrast, jeżeli inne wystarczająco rozpoznawalne cechy identyfikują element.
Niska liczba nie dowodzi więc automatycznie naruszenia WCAG. Najpierw potrzebne są funkcja, rozmiar, stan i rzeczywiste tło. Z kolei nazwa zmiennej, na przykład --border-soft, nie zmienia wymaganej granicy w dekorację.
Przykład możliwy do odtworzenia
Dla nieprzezroczystej barwy tekstu #5e7184 na tle #f1f5f9 wzór WCAG daje około 4,595593:1. Ta konkretna para spełnia poziom AA dla zwykłego tekstu. Wyświetlenie z dwoma miejscami po przecinku daje 4,60:1, ale porównanie nadal wykorzystuje wartość niezaokrągloną.
#777777 na białym tle daje natomiast około 4,478089:1 i nie osiąga 4,5:1. #767676 na białym tle osiąga około 4,542225:1. Mała zmiana barwy może przekroczyć próg. Cel 4,6:1 pozostawia pewien zapas, ale nie gwarantuje spełnienia wymagań po późniejszych zmianach tła.
Poniższy przykład w Pythonie przyjmuje wyłącznie nieprzezroczyste sześciocyfrowe barwy sRGB w zapisie szesnastkowym. Punkt przejścia przy linearyzacji wynosi 0,04045. Starsza wartość 0,03928 wybiera tę samą gałąź dla całkowitych kanałów 8-bitowych; przykład stosuje aktualną definicję. Alfa, gradienty, kaskada CSS i inne przestrzenie barw pozostają poza zakresem programu.
"""WCAG 2.2 ratio for two opaque six-digit sRGB hex colours only."""
import re
def luminance(value):
if not isinstance(value, str) or not re.fullmatch(r"#?[0-9a-fA-F]{6}", value):
raise ValueError("Expected six-digit opaque sRGB hex colour")
value = value.removeprefix("#")
channels = [int(value[i:i+2], 16) / 255 for i in (0, 2, 4)]
linear = [c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4
for c in channels]
return sum(w * c for w, c in zip((0.2126, 0.7152, 0.0722), linear))
def contrast(foreground, background):
a, b = luminance(foreground), luminance(background)
return (max(a, b) + 0.05) / (min(a, b) + 0.05)
if __name__ == "__main__":
ratio = contrast("#5e7184", "#f1f5f9")
print(f"{ratio:.4f}:1; AA normal text: {ratio >= 4.5}")Cztery ograniczenia kontroli samej palety
- Nazwy nie zastępują zastosowania.
--on-accentsugeruje tekst na powierzchni akcentowej, ale CSS może użyć wartości gdzie indziej. Wartość nazwana miękką może również stanowić ważny tekst. - Brak nadpisania nie uruchamia automatycznie wartości zastępczej. Ciemny motyw może dziedziczyć wartości ze wspólnej podstawy. Selektory, kaskada i dziedziczenie określają wartość obliczoną. Wartość zastępcza
var()działa w określonych warunkach; sam brak drugiej deklaracji nie dowodzi błędu. - Przezroczystość i gradienty wymagają rzeczywistego podłoża. Wartość alfa określa przezroczystość. Widoczna barwa powstaje z połączenia częściowo przezroczystej barwy z warstwami poniżej. Obrazy lub gradienty wymagają kontroli najmniej korzystnego istotnego obszaru za tekstem. Obszar może leżeć także wewnątrz gradientu, a nie tylko na końcu.
- Stany zmieniają pary. Fokus, najechanie, zaznaczenie, komunikaty błędów i wyróżnione karty mogą wprowadzać inne tła. Poprawna para domyślna nie zatwierdza wszystkich stanów ani całej witryny.

Fokus i etykiety formularzy
Wskaźnik fokusu oznacza element aktualnie wybrany do obsługi klawiaturą, na przykład widoczną ramką. Wskaźnik zaprojektowany przez autora musi spełniać odpowiednie wymagania rozpoznawalności stanów. WCAG 2.4.13 na poziomie AAA dodaje wymagania dotyczące powierzchni wskaźnika i co najmniej 3:1 pomiędzy tymi samymi pikselami w stanie z fokusem i bez fokusu. To inne porównanie niż kontrola sąsiednich barw według 1.4.11. Niezmieniona prezentacja przeglądarki i inne wyraźnie wymienione przypadki mają osobne wyjątki.
Tekst zastępczy w aktywnym polu wymaga odpowiedniego kontrastu tekstowego. Czytelny placeholder nadal nie zastępuje właściwej etykiety, ponieważ wskazówka znika podczas wpisywania. Cel pola i przykłady powinny pozostać zrozumiałe również w trakcie edycji.
Co potrafi ustalić narzędzie?
Podlinkowany audytor palety oblicza pary barw lokalnie w przeglądarce. Obecna implementacja odczytuje deklaracje wzorcem tekstowym i odgaduje role z nazw. Nie rozwiązuje rzeczywistej kaskady CSS: przy powtórzonej nazwie wygrywa pierwsza znaleziona wartość, a deklaracje w komentarzach także mogą zostać odczytane. Wartości z var() lub oklch() nie są rozwiązywane.
Alfa jest oznaczana, ale nie uczestniczy w obliczaniu kontrastu. Izolowany test z całkowicie przezroczystą czernią na białym tle daje więc 21:1 i dobrą ocenę ogólną mimo ostrzeżenia o alfie. Inny test traktuje --text-soft jako dekorację i wyłącza wartość z ustaleń. Dobry wynik jest zatem tylko wskazówką dotyczącą rozpoznanych hipotetycznych par, a nie potwierdzeniem poprawności wyrenderowanego interfejsu.
Sześć izolowanych testów logiki narzędzia i dwanaście testów przykładu w Pythonie potwierdza te konkretne stwierdzenia. Obliczenia nie zastępują kontroli wizualnej i stanów w przeglądarce. Wiarygodny przegląd obejmuje oba motywy, faktyczne zestawienia barw oraz istotne stany elementów sterujących.
Pytania i odpowiedzi
Czy wyświetlone 4,50 może nadal oznaczać brak spełnienia progu?
Tak. Wartość minimalnie poniżej 4,5 może zaokrąglić się do 4,50. Decyzja musi poprzedzać zaokrąglenie.
Czy blada ramka zawsze jest dekoracją?
Nie. Decyduje funkcja, a nie barwa ani nazwa zmiennej. Informacja potrzebna do obsługi lub zrozumienia wymaga odpowiedniej kontroli.
Czy dwie kompletne palety dowodzą dostępności?
Nie. Kompletność palet i obliczenia kontrastu obejmują tylko część wymagań. Rzeczywisty wygląd, stany, etykiety i inne kryteria WCAG nadal wymagają oddzielnej oceny.


