LW IT Solutions logo LW IT Solutions logo LW IT Solutions
« Przegląd bloga /Tworzenie stron internetowych/Tutorials / Jasne i ciemne palety: kontrola kontrastu i...
Ten artykuł w innych językach:

Jasne i ciemne palety: kontrola kontrastu i ograniczenia

Jasne i ciemne palety: kontrola kontrastu i ograniczeniaJasne 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
  1. Który próg obowiązuje?
  2. Przykład możliwy do odtworzenia
  3. Cztery ograniczenia kontroli samej palety
  4. Fokus i etykiety formularzy
  5. Co potrafi ustalić narzędzie?
  6. Pytania i odpowiedzi
  7. Źródła

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.

Właściwy próg kontrastu, rzeczywisty wygląd i obliczona nieprzezroczysta para sRGB
Właściwy próg kontrastu, rzeczywisty wygląd i obliczona nieprzezroczysta para sRGB.

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.

Python
"""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

  1. Nazwy nie zastępują zastosowania. --on-accent sugeruje 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.
  2. 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.
  3. 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.
  4. 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.
Dwie jednakowe szklane zawieszki wiszą w oknie, jedna przed zasłoną, druga przed ścianą, i wyglądają zupełnie inaczej. Tak samo widoczny odcień przezroczystej powierzchni zależy od rzeczywistego tła.
Dwie jednakowe szklane zawieszki wiszą w oknie, jedna przed zasłoną, druga przed ścianą, i wyglądają zupełnie inaczej. Tak samo widoczny odcień przezroczystej powierzchni zależy od rzeczywistego tła.

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.

Lukas Wójcik

Lukas Wójcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Kontakt

Masz pytanie lub pomysł na projekt internetowy? Napisz krótko, o co chodzi. Formularz korzysta z reCAPTCHA i formconfirmed do ochrony przed spamem.

Napisanie komentarza

Przypadki brzegowe pominięte w artykule i pytania o kod są tu mile widziane.

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

LUKASWOJCIK.COM · NEWSLETTER

Nowe pomysły w skrzynce

Nowe artykuły, praktyczne narzędzia i informacje o projektach.

Wybierz tematy (opcjonalnie)
Bez wyboru: wszystkie tematy.

Zapis wymaga potwierdzenia e-mailem. · Prywatność

Prywatność · Newsletter

Adres e-mail, język, wybrane tematy oraz daty zapisu i potwierdzenia są przechowywane w celu wysyłki newslettera. Wymagane jest potwierdzenie zapisu. Każda wiadomość zawiera link do natychmiastowej rezygnacji. Formconfirmed chroni formularz przed spamem. Brak śledzenia otwarć i kliknięć.

Pełna polityka prywatności ↗