Najczęstsze błędy WCAG od lat są te same, a większość z nich naprawia się prostymi zmianami w kodzie. Raport WebAIM Million 2025, w którym przeanalizowano strony główne miliona popularnych witryn, wykrył automatycznie błędy WCAG 2 na ok. 95% z nich.

Poniżej omawiamy typy błędów z czołówki tego zestawienia – z przykładami kodu „źle/dobrze” i powiązanymi kryteriami – a na końcu kilka problemów spoza listy, które regularnie wychodzą w audytach, choć automat zwykle ich nie wychwyci.

Najczęstsze błędy WCAG według WebAIM Million

Zestawienie WebAIM Million powstaje co roku, a kolejność najczęstszych typów błędów od lat się nie zmienia:

Najczęstsze typy błędów i powiązane kryteria WCAG
BłądKryterium WCAGPoziom
1. Niski kontrast tekstu1.4.3 Contrast (Minimum)AA
2. Brak tekstu alternatywnego obrazów1.1.1 Non-text ContentA
3. Pola formularzy bez etykiet1.3.1, 3.3.2, 4.1.2A
4. Puste linki2.4.4 Link Purpose (In Context), 4.1.2A
5. Puste przyciski4.1.2 Name, Role, ValueA
6. Brak określenia języka dokumentu3.1.1 Language of PageA

To wyłącznie błędy wykrywalne automatycznie, więc realny obraz jest gorszy. Według Deque (2021) testy axe-core wykryły ok. 57% problemów liczonych według liczby wystąpień, a inne badania podają inne wartości. Różnice między metodami opisujemy w artykule test automatyczny a audyt manualny.

Niski kontrast tekstu

Dlaczego to problem
Jasnoszary tekst na białym tle jest trudny do odczytania dla osób słabowidzących, starszych i dla każdego, kto patrzy na ekran w słońcu.
Jak wykryć
Test automatyczny znajdzie większość przypadków na jednolitym tle. Tekst na zdjęciach i gradientach sprawdź ręcznie.
Kryterium
1.4.3 Contrast (Minimum) – kontrast minimalny: 4,5:1 dla zwykłego tekstu, 3:1 dla dużego.
/* Źle: 2,85:1 */
.opis { color: #999999; background: #ffffff; }

/* Dobrze: 4,54:1 */
.opis { color: #767676; background: #ffffff; }

Progi, wzór i typowe pułapki omawiamy w artykule o kontraście kolorów WCAG.

Brak tekstu alternatywnego obrazów

Dlaczego to problem
Użytkownik czytnika ekranu nie wie, co przedstawia obraz, a przy obrazie w linku – dokąd link prowadzi. Czytnik może zamiast tego odczytać nazwę pliku.
Jak wykryć
Brak atrybutu alt wykryje automat. To, czy opis ma sens, oceni tylko człowiek.
Kryterium
1.1.1 Non-text Content – treść nietekstowa.
<!-- Źle -->
<img src="DSC_0192.jpg">

<!-- Dobrze: obraz informacyjny i dekoracyjny -->
<img src="DSC_0192.jpg" alt="Serwisant wymienia filtr w pompie ciepła">
<img src="fala.svg" alt="">

Jak pisać opisy w różnych sytuacjach, wyjaśniamy w poradniku o tekście alternatywnym.

Pola formularzy bez etykiet

Dlaczego to problem
Czytnik ekranu poinformuje tylko, że to pole tekstowe, więc użytkownik nie wie, co wpisać. Placeholder nie zastępuje etykiety: znika przy pisaniu i bywa zbyt jasny.
Jak wykryć
Pola bez nazwy wykryje automat. Czy etykieta jest zrozumiała, sprawdzisz ręcznie.
Kryteria
1.3.1 Info and Relationships – informacje i relacje, 3.3.2 Labels or Instructions – etykiety lub instrukcje, 4.1.2 Name, Role, Value – nazwa, rola, wartość.
<!-- Źle: tekst obok pola nie jest z nim powiązany -->
<span>Kod pocztowy</span>
<input type="text" name="kod">

<!-- Dobrze -->
<label for="kod">Kod pocztowy</label>
<input type="text" id="kod" name="kod" autocomplete="postal-code">

Jeśli etykieta ma być niewidoczna, np. w polu wyszukiwarki obok przycisku z lupą, zostaw element <label> ukryty wizualnie klasą visually-hidden albo nadaj polu atrybut aria-label.

Puste linki i puste przyciski

Dlaczego to problem
Link lub przycisk bez tekstu czytnik ogłosi jako sam „link” czy „przycisk” albo odczyta adres URL, a osoba sterująca głosem nie ma jak go nazwać. Zwykle chodzi o ikony: koszyk, wyszukiwarkę, menu, strzałki karuzeli, media społecznościowe.
Jak wykryć
Brak nazwy automat wykrywa dobrze. Ręcznie sprawdź, czy nazwa jest zrozumiała.
Kryteria
2.4.4 Link Purpose (In Context) – cel linku (w kontekście) oraz 4.1.2 Name, Role, Value.
<!-- Źle -->
<button type="button" class="menu-toggle"><svg>…</svg></button>
<a href="/koszyk"><i class="icon-cart"></i></a>

<!-- Dobrze -->
<button type="button" class="menu-toggle" aria-expanded="false">
  <svg aria-hidden="true">…</svg> Menu
</button>
<a href="/koszyk">
  <i class="icon-cart" aria-hidden="true"></i>
  <span class="visually-hidden">Koszyk</span>
</a>

Nazwę można też nadać atrybutem aria-label, ale widoczny podpis pomaga wszystkim użytkownikom, nie tylko tym, którzy korzystają z czytników ekranu.

Brak określenia języka strony

Dlaczego to problem
Czytnik ekranu dobiera wymowę do języka dokumentu. Bez atrybutu lang polski tekst może zostać przeczytany z angielską wymową i stać się niezrozumiały. Język wpływa też na automatyczne tłumaczenie i dzielenie wyrazów.
Jak wykryć
Automatycznie i bez trudu – to jeden z testów bezpłatnego skanu wstępnego na stronie głównej. Ręcznie sprawdź, czy język jest właściwy: motyw ustawiający lang="en-US" na polskiej stronie to także błąd.
Kryterium
3.1.1 Language of Page – język strony. Fragmenty w innym języku obejmuje 3.1.2 Language of Parts – język części (AA).
<!-- Źle -->
<html>

<!-- Dobrze -->
<html lang="pl">
…
<p>Hasło ruchu: <span lang="en">Nothing about us without us</span></p>

W WordPressie język strony ustawisz w menu Ustawienia → Ogólne → Język witryny. Motyw powinien przekazać go do znacznika <html> – sprawdź to w kodzie strony.

Częste błędy, których automat zwykle nie wychwyci

Te problemy łatwo przeoczyć, bo ujawniają się dopiero podczas obsługi strony klawiaturą lub czytnikiem ekranu, a nie w samej analizie kodu.

Niewidoczny fokus

Reguła outline: none bez zamiennika sprawia, że osoba korzystająca z klawiatury nie wie, gdzie jest. To naruszenie 2.4.7 Focus Visible – widoczny fokus (AA). Wykryjesz je, przechodząc stronę klawiszem Tab.

/* Źle */
:focus { outline: none; }

/* Dobrze: wyraźny obrys z kontrastem co najmniej 3:1 względem tła */
:focus-visible { outline: 3px solid #1a56db; outline-offset: 2px; }

Pułapka klawiaturowa w oknie modalnym

Skrypt zatrzymuje fokus w oknie, ale przycisk zamknięcia to <div> bez obsługi klawiatury, a Esc nie działa – użytkownik utknął. To naruszenie 2.1.2 No Keyboard Trap – brak pułapki klawiaturowej (A). Odwrotny błąd to fokus uciekający pod otwarte okno, do zasłoniętej treści (2.4.3 Focus Order – kolejność fokusu). Dużą część pracy wykona natywny element <dialog> otwierany metodą showModal(): blokuje resztę strony i zamyka się klawiszem Esc.

<dialog id="dostawa" aria-labelledby="dostawa-tytul">
  <h2 id="dostawa-tytul">Koszty dostawy</h2>
  …
  <form method="dialog"><button>Zamknij</button></form>
</dialog>

Po zamknięciu okna fokus powinien wrócić do przycisku, który je otworzył – sprawdź to klawiaturą.

Komunikaty błędów w formularzach

Pole obrysowane na czerwono bez żadnego tekstu to za mało: osoba niewidoma lub nierozróżniająca kolorów nie wie, co poszło nie tak. Kryterium 3.3.1 Error Identification – identyfikacja błędów (A) wymaga opisania błędu tekstem, a 1.4.1 Use of Color – użycie koloru (A) nie pozwala przekazywać informacji wyłącznie kolorem. Powiąż komunikat z polem:

<label for="kod">Kod pocztowy</label>
<input id="kod" name="kod" aria-invalid="true" aria-describedby="kod-blad">
<p id="kod-blad">Wpisz kod w formacie 00-000.</p>

Podpowiedz też, jak poprawić błąd – tego wymaga 3.3.3 Error Suggestion – sugestia poprawy (AA). Po wysłaniu formularza przenieś fokus do pierwszego błędnego pola albo do podsumowania błędów na początku formularza.

Nagłówki udające tekst i tekst udający nagłówki

Czytniki ekranu pozwalają przeskakiwać po nagłówkach jak po spisie treści. Śródtytuł zrobiony z pogrubionego akapitu w tym spisie się nie pojawi. Z kolei <h3> użyty tylko po to, żeby napis był większy, zaśmieca strukturę. Oba przypadki dotyczą 1.3.1 Info and Relationships. Wygląd ustawiaj w CSS, a poziom nagłówka dobieraj do struktury treści.

<!-- Źle -->
<p class="duzy-pogrubiony">Dane do wysyłki</p>
<h3>Nowość w ofercie!</h3>

<!-- Dobrze -->
<h2>Dane do wysyłki</h2>
<p class="wyroznienie">Nowość w ofercie!</p>

Linki „Czytaj więcej”

Lista linków w czytniku ekranu pokaże wiele razy „Czytaj więcej” bez informacji, czego dotyczą. Kryterium 2.4.4 dopuszcza ustalenie celu linku z otoczenia, np. z tego samego akapitu, ale osobie przeglądającej samą listę linków to nie pomoże. Najlepiej pisz linki opisowe. Jeśli projekt wymaga krótkiego napisu, dodaj ukryte uzupełnienie tak, żeby nazwa linku zawierała widoczny tekst – wymaga tego 2.5.3 Label in Name – etykieta w nazwie (A).

<!-- Słabo -->
<a href="/blog/kontrast">Czytaj więcej</a>

<!-- Lepiej -->
<a href="/blog/kontrast">Czytaj więcej<span class="visually-hidden"> o kontraście kolorów</span></a>

Jak naprawiać najczęstsze błędy WCAG

  • Poprawiaj u źródła: w szablonie, komponencie, zmiennej koloru. Jedna zmiana naprawia wtedy błąd na wszystkich podstronach.
  • Zacznij od blokad na kluczowych ścieżkach: formularze, koszyk, logowanie, nawigacja klawiaturą.
  • Uruchom test automatyczny, żeby znaleźć powtarzalne błędy z listy WebAIM.
  • Przejdź najważniejsze ścieżki klawiaturą i czytnikiem ekranu według poradnika jak sprawdzić stronę pod kątem WCAG.
  • Zapobiegaj nawrotom: wytyczne o tekstach alternatywnych dla redakcji, kolory sprawdzone w design systemie, kontrola dostępności przed każdym wdrożeniem.

Najczęstsze pytania

Czy nakładka lub wtyczka dostępności usunie te błędy?

Nie. Nakładki typu „jeden skrypt” nie naprawiają kodu strony i nie zapewniają zgodności z WCAG, a mogą kolidować z technologiami asystującymi. Błędy trzeba poprawić w szablonie i treści.

Czy brak błędów w teście automatycznym oznacza, że strona jest zgodna z WCAG?

Nie. Automat sprawdza tylko część wymagań, a sensowność opisów, obsługa klawiaturą czy zrozumiałość komunikatów wymagają ręcznej weryfikacji. Wynik testu automatycznego nie jest certyfikatem ani potwierdzeniem zgodności.

Jak często sprawdzać stronę pod kątem tych błędów?

Najlepiej przy każdej większej zmianie: nowym szablonie, redesignie, nowej wtyczce czy kampanii z nowymi banerami. Część błędów, np. brak tekstów alternatywnych, wraca razem z nowymi treściami, więc warto sprawdzać stronę regularnie.