Zamów stronę

Jeden odblask pod jedną literą — i błąd, którego żaden test nie mógł złapać

przez Łukasz Jajor | sie 18, 2026 | Z warsztatu | 0 komentarzy

Studio iFOX · seria „Z warsztatu", odc. 4

Poprzednio napisaliśmy, że tym razem nie deklarujemy końca serii. Dobrze, bo oto czwarty odcinek.

Scena jest zawsze podobna. Projekt zaakceptowany, hero wygląda świetnie — bo projektant dobierał zdjęcie i pozycję nagłówka razem, jedno pod drugie. Pół roku później ktoś od marketingu podmienia fotografię na własną, z sesji. Wymiary się zgadzają, kadr się zgadza, strona działa.

Tylko nagłówka już nie widać. A właściwie widać, ale nie cały: „B" i „u" wsiąkły w jasną chmurę, reszta słowa została.

Nikt tego nie zgłosi. Zdjęcie jest w porządku, tekst jest w porządku, kod jest w porządku. Nie zgadza się dopiero jedno z drugim.

Średnia niczego nie mówi

Tu jest sedno i powód, dla którego popularne sprawdzanie kontrastu w hero jest sprawdzaniem czegoś innego, niż się wydaje.

Standardowe podejście: bierzemy prostokąt, w którym leży tekst, liczymy średnią jasność pikseli, porównujemy z kolorem tekstu. Wychodzi liczba, liczba jest zielona, idziemy dalej.

Problem w tym, że średnia nie jest tym, co czyta człowiek. Zdjęcie z ciemnym lasem i jednym jasnym prześwitem między drzewami ma niską średnią jasność — i całkowicie nieczytelne słowo dokładnie tam, gdzie wypadł prześwit. Uśrednienie zamiata problem, bo problem jest lokalny z definicji.

Czytelność nagłówka nie zależy od tego, jak jasne jest zdjęcie. Zależy od najgorszego miejsca pod literami.

To brzmi jak drobiazg metodologiczny, ale zmienia całą konstrukcję pomiaru. Nie wystarczy wziąć obszaru tekstu — trzeba wiedzieć, gdzie dokładnie stoją glify. Dlatego nasze narzędzie renderuje wpisany nagłówek, bierze maskę liter i sprawdza kontrast piksel po pikselu wyłącznie tam, gdzie faktycznie jest litera. Nie w prostokącie wokół niej.

Efekt uboczny okazał się najbardziej użyteczny: skoro wiemy, które piksele nie przechodzą, można je pokazać. Narzędzie maluje je na czerwono wprost na zdjęciu. Nie dostajesz komunikatu „za mały kontrast", tylko widzisz, że rozjaśniony róg zjada dokładnie dwie pierwsze litery.

Próg nie jest jeden i to zaskakuje

Druga rzecz, o której wie mało kto, a która wywraca ocenę „czy to jest czytelne".

WCAG nie ma jednego progu dla tekstu na obrazie. Duży tekst — od 24 px, albo od 18,7 px przy grubej odmianie — wymaga 3:1. Wszystko mniejsze wymaga 4,5:1.

Praktyczna konsekwencja jest taka, że w tym samym hero, na tym samym zdjęciu, w tym samym miejscu:

  • nagłówek 54 px bold może przechodzić bez zastrzeżeń
  • leżący pod nim podtytuł 18 px może nie przechodzić

To nie jest teoria. To najczęstszy układ hero, jaki się buduje. Zdjęcie sprawdzone „na nagłówku" nie jest sprawdzone dla podtytułu, a podtytuł to zwykle właśnie to zdanie, które ma coś wytłumaczyć.

Dlatego w narzędziu jest suwak szerokości hero obok stopnia pisma. Nie dla wygody — od tych dwóch liczb zależy, jak duże będą litery u odwiedzającego, a więc i który próg w ogóle obowiązuje.

Ile przyciemnienia naprawdę trzeba

Nakładka pod tekstem to standardowe rozwiązanie i wszyscy je stosują. Zwykle na oko: ktoś ustawia 40%, patrzy, dodaje do 50%, wygląda okej, zostaje.

To da się policzyć dokładnie. Warstwa o kryciu α miesza się z tłem według prostego wzoru, więc wystarczy rozwiązać go wstecz: szukamy najmniejszego krycia, przy którym najgorszy piksel pod literami przechodzi próg.

Konkretny przykład z naszych testów. Biały tekst na jasnym niebie o wartości rgb(223, 233, 239):

krycie czarnej warstwykontrast
brak1,23:1
20%1,96:1
40%3,42:1
60%6,63:1

Minimum dla progu 3:1 wypada na 36%. Dla 4,5:1 — na 49%. Czyli popularne „ustawię 40%" jest wystarczające dla nagłówka i za słabe dla podtytułu pod nim. Dokładnie ta pułapka z poprzedniej sekcji, tylko z liczbami.

I granica, o której warto mówić głośno: powyżej mniej więcej 70% krycia ze zdjęcia praktycznie nic nie zostaje. Jeśli wyliczenie wychodzi wyżej, to nie jest informacja o warstwie, tylko o kadrze. Narzędzie mówi to wprost, zamiast podawać liczbę i udawać, że sprawa załatwiona.

Błąd, którego żaden test nie mógł złapać

Silnik przeszedł wszystko, co mu podłożyliśmy. Wartości zgadzały się z ręcznie policzoną referencją co do procenta — 36% i 49% dokładnie tam, gdzie powinny.

A potem ktoś wybrał ciemny tekst.

Warstwa pod ciemnym tekstem musi być biała, nie czarna — inaczej pogarsza sytuację zamiast poprawiać. Silnik robił to poprawnie od początku: dobiera kolor warstwy automatycznie, patrząc na jasność tekstu. Liczby były prawidłowe.

Tylko że cały interfejs mówił „warstwa przyciemniająca". Suwak nazywał się kryciem przyciemnienia, komunikaty mówiły o przyciemnianiu, sekcja miała nagłówek z przyciemnianiem.

Użytkownik wybierał ciemny tekst, przesuwał suwak i patrzył, jak zdjęcie jaśnieje — pod kontrolką, która obiecywała coś odwrotnego. Wynik był poprawny. Narzędzie było nie do zrozumienia.

Tego nie wykryłby żaden test jednostkowy, bo nic się nie psuło. Wyszło przypadkiem, przy sprawdzaniu zupełnie innej sprawy — czy pomarańczowy tekst da się uratować samą warstwą. Odpowiedź brzmiała „tak, ale przy 87% krycia", i dopiero patrząc na tę liczbę zauważyliśmy, że mówimy o rozjaśnianiu, nazywając je przyciemnianiem.

To chyba najbardziej pouczająca z wszystkich wpadek w tej serii. Poprzednie były błędami w liczbach — takie się znajduje testami. Ta była błędem w słowach i przeszła przez wszystkie testy śpiewająco.

Co z tego wynika dla Twojej strony

Za każdym razem, gdy ktoś podmienia zdjęcie w hero, sprawdź nagłówek ponownie. Podmiana fotografii jest niewinną czynnością — i jedyną, która potrafi jednym ruchem unieważnić decyzję projektową sprzed pół roku.

Sprawdź osobno nagłówek i podtytuł. To dwa różne progi i bardzo często dwa różne wyniki.

A jeśli wyliczone przyciemnienie wychodzi bardzo wysokie, nie podkręcaj go dalej. To znaczy, że zdjęcie i tekst nie chcą w tym miejscu współpracować — i taniej jest przesunąć nagłówek albo zmienić kadr niż zamalować fotografię, za którą klient zapłacił.


Prześwit jest darmowy i nie wymaga logowania: sprawdź swoje hero — kontrast liczony pod maską liter, mapa nieczytelnych fragmentów, minimalne krycie warstwy i gotowy CSS. Zdjęcie czytane jest lokalnie i nigdzie nie wychodzi.

Cztery narzędzia, cztery odcinki. Kolor, krój, typografia i czytelność na zdjęciu — za każdym razem ta sama zasada: zmierzyć, zamiast zadeklarować.