Kurs HTML i CSS · Moduł 10: Dostępność (a11y)

Testowanie dostępności

7 min czytania
W tej lekcji6

Zbudowałeś stronę muzeum zgodnie ze wszystkimi zasadami z tego modułu. Skąd jednak wiesz, że naprawdę działa? Łatwo przeoczyć brakujący alt albo pole bez etykiety, dopóki sam nie przejdziesz strony tak jak inni. Nawet najlepsza wiedza o dostępności nie zastąpi praktycznego testowania. Tak jak archeolodzy systematycznie przeszukują stanowiska wykopaliskowe, tak my musimy systematycznie testować nasze strony pod kątem dostępności, używając różnych narzędzi i metod.

Testy idą od najszybszych do najbardziej wymagających: najpierw automat (Lighthouse lub axe), potem test klawiatury, następnie czytnik ekranowy, a na końcu testy z użytkownikami z niepełnosprawnościami. Każdy etap łapie błędy, których poprzedni nie widzi.

Automatyczne narzędzia

Lighthouse (wbudowany w Chrome DevTools)

Lighthouse to bezpłatne narzędzie Google, które można uruchomić bezpośrednio z Chrome DevTools:

  1. Otwórz DevTools (F12)
  2. Przejdź do zakładki "Lighthouse"
  3. Zaznacz "Accessibility"
  4. Kliknij "Analyze page load"

Lighthouse sprawdza m.in.:

  • Czy obrazy mają tekst alternatywny
  • Czy kontrast kolorów jest wystarczający
  • Czy elementy formularzy mają etykiety
  • Czy strona ma poprawną hierarchię nagłówków

Uwaga: wynik 100 nie oznacza, że strona jest w pełni dostępna. Automat sprawdzi, czy obraz ma alt, ale nie oceni, czy ten alt ma sens - dlatego po nim zawsze przychodzą testy ręczne.

axe DevTools

axe to jedno z najpopularniejszych narzędzi do testowania dostępności - rozszerzenie przeglądarki oparte na silniku axe-core, z którego korzysta też Lighthouse. Każdy problem opisuje w stałym formacie:

1<!-- Wynik testu axe może wyglądać tak: -->
2<!--
3  Violation: Images must have alternate text
4  Element: <img src="pharaoh.jpg">
5  Fix: Add an alt attribute to the image
6  Impact: Critical
7  WCAG: 1.1.1 (Level A)
8-->

Raport mówi, co jest źle, jak to naprawić, jak poważny jest problem (Impact) i którego kryterium WCAG dotyczy - tutaj 1.1.1, czyli tekstów alternatywnych.

HTML Validator (W3C)

Poprawny HTML to fundament dostępności, bo czytniki polegają na drzewie elementów zbudowanym z Twojego kodu. Walidator wykryje błędy, które to drzewo psują:

1<!-- Błędy wykrywane przez walidator: -->
2
3<!-- Błąd: Brak atrybutu alt -->
4<img src="photo.jpg">
5
6<!-- Błąd: Zduplikowane ID -->
7<input id="name">
8<label id="name">
9
10<!-- Błąd: Niepoprawne zagnieżdżenie -->
11<p>Tekst <div>w divie</div> w paragrafie</p>

Zduplikowane id psuje powiązania for i aria-describedby, a <div> wewnątrz <p> sprawia, że przeglądarka zamyka akapit wcześniej, niż zamierzałeś. Walidator poznasz bliżej w następnym module.

Ręczne testowanie

Test klawiatury

Najprostszy test ręczny: odłóż myszkę i przejdź całą stronę klawiszami Tab, Shift+Tab, Enter i Escape, odhaczając kolejne punkty:

1Checklist nawigacji klawiaturowej:
2[ ] Czy można dotrzeć do każdego interaktywnego elementu Tabem?
3[ ] Czy kolejność focusu jest logiczna?
4[ ] Czy focus jest zawsze widoczny?
5[ ] Czy modalne okna dialogowe przechwytują focus?
6[ ] Czy można zamknąć modal klawiszem Escape?
7[ ] Czy skip link działa poprawnie?
8[ ] Czy formularze można wysłać Enterem?
9[ ] Czy rozwijane menu można nawigować strzałkami?

Test trwa kilka minut, a wykrywa to, czego automat nie zobaczy, np. focus znikający w ukrytym menu. Wyślij też pusty formularz i sprawdź, czy komunikaty prowadzą Cię do błędnych pól.

Test czytnika ekranowego

Czytnik ekranowy to jedyny sposób, by usłyszeć stronę tak, jak słyszy ją osoba niewidoma. Popularne czytniki ekranowe:

  • NVDA (Windows, bezpłatny) - www.nvaccess.org
  • VoiceOver (macOS/iOS, wbudowany) - Cmd + F5
  • JAWS (Windows, płatny) - profesjonalny standard
  • TalkBack (Android, wbudowany)

Na początek wystarczy VoiceOver lub darmowy NVDA - posłuchaj, czy pola mają sensowne nazwy. Ostatnim, najcenniejszym etapem są testy z użytkownikami z niepełnosprawnościami - nikt nie zna ich potrzeb lepiej niż oni sami.

Test powiększania

Osoby słabowidzące powiększają stronę, zamiast mrużyć oczy nad drobnym tekstem. Powiększysz ją skrótem Ctrl i + (Cmd i + na Macu):

1Checklist testu powiększania:
2[ ] Powiększ stronę do 200% - czy cała treść jest widoczna?
3[ ] Powiększ do 400% - czy strona nadal działa?
4[ ] Czy tekst się nie ucina i nie nakłada?
5[ ] Czy scrollowanie jest tylko w jednym kierunku?

Progi pochodzą z WCAG: kryterium 1.4.4 wymaga powiększenia tekstu do 200% bez utraty treści, a 1.4.10 - braku przewijania w dwóch kierunkach przy szerokości 320 pikseli CSS, czyli przy 400% na ekranie 1280px.

Chrome DevTools - Accessibility

Panel Accessibility

DevTools pokażą, jak przeglądarka "tłumaczy" element dla czytnika. Zaznacz element w panelu Elements i otwórz kartę Accessibility:

1Chrome DevTools > Elements > Accessibility:
2- Name: "Zamknij" (z aria-label)
3- Role: button
4- Focusable: true
5- Description: "Zamknij okno dialogowe"

Name to dostępna nazwa elementu, a Role mówi, czym on jest. Puste Name oznacza, że czytnik nie ma czego odczytać - właśnie znalazłeś błąd.

Symulacja wad wzroku

DevTools potrafią też pokazać stronę oczami osoby z zaburzeniami widzenia. Chrome DevTools > Rendering > Emulate vision deficiencies:

  • Protanopia (brak czerwonego)
  • Deuteranopia (brak zielonego)
  • Tritanopia (brak niebieskiego)
  • Blurred vision (nieostre widzenie)

Panel Rendering otworzysz z menu DevTools (More tools). Włącz protanopię i zobacz, czy czerwona ramka błędu nadal się wyróżnia.

Inspekcja kontrastu

Kontrast sprawdzisz bez wychodzenia z DevTools. W karcie Styles kliknij kwadracik koloru obok właściwości color:

1Chrome DevTools > Elements > Styles:
2- Kliknij kwadracik koloru przy właściwości color
3- Selektor kolorów pokaże Contrast ratio
4- Znacznik przy AA = tekst spełnia próg 4.5:1
5- Znacznik przy AAA = spełnia też próg 7:1
6- Brak znacznika = kontrast za niski

Kolor możesz tam przesuwać, aż kontrast osiągnie wymagany próg.

Automatyzacja testów a11y

eslint-plugin-jsx-a11y (React)

Gdy zaczniesz pisać w React w świecie Podróży w Kosmos, linter ESLint z wtyczką jsx-a11y wyłapie błędy dostępności już podczas pisania kodu:

1{
2  "plugins": ["jsx-a11y"],
3  "rules": {
4    "jsx-a11y/alt-text": "error",
5    "jsx-a11y/anchor-has-content": "error",
6    "jsx-a11y/label-has-associated-control": "error",
7    "jsx-a11y/no-noninteractive-element-interactions": "warn"
8  }
9}

Każda reguła to jedno sprawdzenie - alt-text zgłosi obraz bez tekstu alternatywnego, a label-has-associated-control pole bez etykiety. Poziom "error" traktuje problem jak błąd, a "warn" tylko ostrzega.

axe-core w testach

Silnik axe-core możesz też uruchamiać w testach automatycznych, żeby każda zmiana w kodzie była sprawdzana bez Twojego udziału:

1<!-- Przykład wyniku testu axe-core: -->
2<!--
3  Rule: color-contrast
4  Description: Elements must have sufficient color contrast
5  Help: Fix any of the following:
6    Element has insufficient color contrast of 2.5:1
7    Expected minimum: 4.5:1
8  Target: .subtitle
9-->

Reguła color-contrast znalazła tekst o kontraście 2.5:1 przy wymaganym 4.5:1 i wskazała selektor .subtitle - wiesz dokładnie, co poprawić.

Checklist dostępności - kompletna lista

Na koniec lista kontrolna całego modułu, ułożona od fundamentów - semantyki i języka strony - po zaawansowane atrybuty ARIA:

1<!-- Struktura HTML -->
2<!-- [ ] Poprawna hierarchia nagłówków (h1-h6) -->
3<!-- [ ] Semantyczne znaczniki (header, nav, main, footer) -->
4<!-- [ ] Język strony (lang="pl") -->
5
6<!-- Obrazy -->
7<!-- [ ] Alt text dla obrazów informacyjnych -->
8<!-- [ ] Pusty alt="" dla dekoracyjnych -->
9
10<!-- Nawigacja -->
11<!-- [ ] Skip link -->
12<!-- [ ] Widoczny focus -->
13<!-- [ ] Logiczna kolejność Tab -->
14
15<!-- Formularze -->
16<!-- [ ] Label dla każdego pola -->
17<!-- [ ] Komunikaty o błędach -->
18<!-- [ ] aria-required dla wymaganych pól -->
19
20<!-- Kolor i kontrast -->
21<!-- [ ] Kontrast minimum 4.5:1 -->
22<!-- [ ] Informacja nie tylko przez kolor -->
23
24<!-- Multimedia -->
25<!-- [ ] Napisy do wideo -->
26<!-- [ ] Transkrypcje do audio -->
27
28<!-- ARIA -->
29<!-- [ ] aria-label dla przycisków-ikon -->
30<!-- [ ] aria-live dla dynamicznych treści -->
31<!-- [ ] aria-expanded dla rozwijanek -->

Idź od góry: bez semantyki i lang nawet najlepsze ARIA nie pomoże. Przy przyciskach-ikonach sprawdź też, czy sama ikona ma aria-hidden="true", żeby czytnik odczytał tylko nazwę z aria-label.

Testowanie dostępności to jak weryfikacja, czy każdy korytarz w piramidzie prowadzi dokąd powinien - systematyczne sprawdzanie każdego elementu, aby upewnić się, że każdy odwiedzający dotrze do celu. W projekcie końcowym tego modułu przejdziesz tę listę na własnej stronie.

Praktyka

Przejdź interaktywną checklistę z edytora poniżej punkt po punkcie:

Kod do tej lekcji: index.html
1<!DOCTYPE html>
2<html lang="pl">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Testowanie dostepnosci - checklist</title>
7    <link rel="stylesheet" href="style.css">
8</head>
9<body>
10    <h1>Checklist testowania dostepnosci</h1>
11
12    <section>
13        <h2>1. Test klawiatury</h2>
14        <p>Nawiguj po tej stronie uzywajac <kbd>Tab</kbd> i sprawdz:</p>
15        <ul class="checklist">
16            <li><label><input type="checkbox"> Kazdy element interaktywny jest osiagalny Tabem</label></li>
17            <li><label><input type="checkbox"> Focus jest widoczny na kazdym elemencie</label></li>
18            <li><label><input type="checkbox"> Kolejnosc focusu jest logiczna</label></li>
19            <li><label><input type="checkbox"> Przyciski reaguja na Enter i Spacje</label></li>
20        </ul>
21    </section>
22
23    <section>
24        <h2>2. Test struktury HTML</h2>
25        <ul class="checklist">
26            <li><label><input type="checkbox"> Strona ma poprawna hierarchie h1-h6</label></li>
27            <li><label><input type="checkbox"> Uzyto semantycznych znacznikow</label></li>
28            <li><label><input type="checkbox"> Jezyk strony jest okreslony (lang="pl")</label></li>
29            <li><label><input type="checkbox"> Wszystkie ID sa unikalne</label></li>
30        </ul>
31    </section>
32
33    <section>
34        <h2>3. Test obrazow</h2>
35        <div class="test-area">
36            <figure>
37                <img src="https://placehold.co/300x200/d4af37/1a1a2e?text=Sfinks"
38                     alt="Wielki Sfinks w Gizie strzegacy piramid">
39                <figcaption>Wielki Sfinks - obraz z tekstem alt</figcaption>
40            </figure>
41            <img src="https://placehold.co/400x3/d4af37/d4af37" alt="">
42            <p><em>Dekoracyjna linia powyzej ma alt=""</em></p>
43        </div>
44        <ul class="checklist">
45            <li><label><input type="checkbox"> Informacyjne obrazy maja opisowy alt</label></li>
46            <li><label><input type="checkbox"> Dekoracyjne obrazy maja alt=""</label></li>
47        </ul>
48    </section>
49
50    <section>
51        <h2>4. Test formularzy</h2>
52        <form class="test-form">
53            <div class="form-group">
54                <label for="test-name">Imie:</label>
55                <input type="text" id="test-name" aria-required="true">
56            </div>
57            <div class="form-group">
58                <label for="test-email">Email:</label>
59                <input type="email" id="test-email"
60                       aria-describedby="test-email-hint">
61                <p id="test-email-hint" class="hint">Format: jan@example.com</p>
62            </div>
63            <button type="button" onclick="validateForm()">Sprawdz formularz</button>
64            <div id="form-result" aria-live="polite"></div>
65        </form>
66        <ul class="checklist">
67            <li><label><input type="checkbox"> Kazde pole ma label</label></li>
68            <li><label><input type="checkbox"> Wymagane pola oznaczone aria-required</label></li>
69            <li><label><input type="checkbox"> Bledy opisane aria-describedby</label></li>
70        </ul>
71    </section>
72
73    <section>
74        <h2>5. Test kontrastu</h2>
75        <div class="contrast-test">
76            <p class="pass-aa">Ten tekst spelnia WCAG AA (kontrast > 4.5:1)</p>
77            <p class="fail">Ten tekst NIE spelnia wymagan (kontrast < 3:1)</p>
78        </div>
79        <ul class="checklist">
80            <li><label><input type="checkbox"> Kontrast tekstu minimum 4.5:1</label></li>
81            <li><label><input type="checkbox"> Informacja nie tylko przez kolor</label></li>
82        </ul>
83    </section>
84
85    <script>
86    function validateForm() {
87        const name = document.getElementById('test-name').value;
88        const result = document.getElementById('form-result');
89        if (!name) {
90            result.innerHTML = '<p class="error" role="alert">Wypelnij pole Imie!</p>';
91        } else {
92            result.innerHTML = '<p class="success">Formularz poprawny!</p>';
93        }
94    }
95    </script>
96</body>
97</html>

Pamiętaj: automat to pierwszy strażnik u wejścia do piramidy, ale dopiero przejście korytarzy z klawiaturą i czytnikiem pokaże, czy każdy dotrze do komnaty.

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Gdzie można uruchomić narzędzie Lighthouse do testowania dostępności?

  2. 2. Co robi media query @media (prefers-reduced-motion: reduce)?

Zadania praktyczne w grze

  • Układanie w pionie

    Ułóż etapy testowania dostępności od automatycznego do ręcznego:

  • Układanie w pionie

    Ułóż poprawną strukturę elementu figure z opisem:

  • Układanie w pionie

    Ułóż poprawne media query do wyłączenia animacji:

  • Edytor kodu

    Przetestuj formularz - kliknij Wyślij bez wypełniania pól. Sprawdź jak aria-invalid, aria-describedby i role="alert" informują o błędach.

  • Klikanie w kolejności

    Ułóż poprawny komunikat błędu z atrybutami ARIA:

  • Układanie w pionie

    Ułóż elementy checklisty a11y od najważniejszych (fundamenty) do zaawansowanych:

  • Układanie w poziomie

    Ułóż poprawną składnię linku aktualnej strony z aria-current:

  • Klikanie w kolejności

    Ułóż poprawny przycisk z ikoną i aria-label:

  • Układanie w pionie

    Ułóż landmark roles w typowej kolejności na stronie (od góry do dołu):

  • Edytor kodu

    Znajdź i napraw wszystkie 8 błędów dostępności na tej stronie. Każdy błąd jest oznaczony komentarzem.

Przydatne artykuły