Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Dostępność (Accessibility) w HTML - budowanie dla wszystkich

Witaj w Świątyni Uniwersalnej Wiedzy! Podobnie jak starożytni Egipcjanie budowali piramidy z szerokich, dostępnych schodów dla wszystkich, którzy chcieli wejść do wnętrza, tak i my musimy budować strony internetowe dostępne dla wszystkich użytkowników - w tym osób z niepełnosprawnościami. Poznaj ARIA i semantyczne HTML - klucze do tworzenia inkluzywnego internetu!

Czym jest Accessibility (A11y)?

Accessibility (w skrócie a11y - "a" + 11 liter + "y") to zapewnienie, że strony internetowe mogą być używane przez wszystkich, niezależnie od ich możliwości fizycznych lub technicznych.

Kto korzysta z dostępnych stron:

  • Osoby niewidome i słabowidzące (czytniki ekranu)
  • Osoby niesłyszące (napisy, transkrypcje)
  • Osoby z problemami motorycznymi (nawigacja klawiaturą)
  • Osoby starsze (większe czcionki, wysoki kontrast)
  • Użytkownicy wolnych połączeń (lekkie strony)

Analogia egipska: Jak hieroglify były zrozumiałe dla kapłanów, pisarzy i zwykłych ludzi na różnych poziomach, tak strona powinna być dostępna dla wszystkich użytkowników.

Semantyczne znaczniki vs div z rolami

Semantyczne HTML - pierwszy krok do dostępności

1<!-- ❌ ZŁE - divs bez znaczenia -->
2<div class="header">
3  <div class="nav">
4    <div class="nav-item">Home</div>
5    <div class="nav-item">About</div>
6  </div>
7</div>
8
9<div class="main-content">
10  <div class="article">
11    <div class="article-title">Tytuł artykułu</div>
12    <div class="article-text">Treść artykułu...</div>
13  </div>
14</div>
15
16<!-- ✅ DOBRE - semantyczne znaczniki -->
17<header>
18  <nav>
19    <a href="/">Home</a>
20    <a href="/about">About</a>
21  </nav>
22</header>
23
24<main>
25  <article>
26    <h1>Tytuł artykułu</h1>
27    <p>Treść artykułu...</p>
28  </article>
29</main>

Dlaczego semantyczne znaczniki są lepsze:

  • ✅ Czytniki ekranu automatycznie rozpoznają strukturę
  • ✅ Wyszukiwarki lepiej indeksują zawartość (SEO)
  • ✅ Przeglądarki zapewniają domyślne zachowania
  • ✅ Łatwiejsze utrzymanie kodu
  • ✅ Nawigacja klawiaturą działa out-of-the-box

Kluczowe semantyczne znaczniki

1<!-- Struktura strony -->
2<header>Logo i nawigacja główna</header>
3<nav>Menu nawigacyjne</nav>
4<main>Główna treść strony (tylko jeden na stronie!)</main>
5<article>Samodzielna jednostka treści (post bloga, artykuł)</article>
6<section>Tematyczna sekcja dokumentu</section>
7<aside>Treść poboczna, powiązana z główną treścią</aside>
8<footer>Stopka sekcji lub strony</footer>
9
10<!-- Zawartość tekstowa -->
11<h1>, <h2>, <h3>, <h4>, <h5>, <h6>Nagłówki w hierarchii</h1>
12<p>Paragraf tekstu</p>
13<blockquote>Cytat</blockquote>
14<figure>Ilustracja z opisem</figure>
15<figcaption>Podpis do ilustracji</figcaption>
16
17<!-- Interaktywne elementy -->
18<button>Przycisk (do akcji)</button>
19<a href="#">Link (do nawigacji)</a>
20<form>Formularz</form>
21<input>, <select>, <textarea>Pola formularza</input>

ARIA - Accessible Rich Internet Applications

ARIA to zestaw atrybutów, które rozszerzają semantykę HTML i pomagają technologiom asystującym (czytniki ekranu) zrozumieć interfejs.

Złota zasada ARIA:

"Nie używaj ARIA, jeśli możesz użyć semantycznego HTML!"

ARIA Roles - definiowanie roli elementu

Role mówią czytnikowi ekranu, czym jest dany element:

1<!-- Kiedy semantyczny HTML NIE wystarcza -->
2
3<!-- ❌ Bez role - nie jest jasne, co to jest -->
4<div class="navigation">
5  <a href="/">Home</a>
6  <a href="/products">Products</a>
7</div>
8
9<!-- ✅ Z role="navigation" -->
10<div role="navigation">
11  <a href="/">Home</a>
12  <a href="/products">Products</a>
13</div>
14
15<!-- ✅ NAJLEPSZE - semantyczny tag (nie potrzeba role!) -->
16<nav>
17  <a href="/">Home</a>
18  <a href="/products">Products</a>
19</nav>

Najpopularniejsze ARIA roles:

1<!-- Nawigacja -->
2<div role="navigation">Menu</div>
3<!-- Lepiej: <nav> -->
4
5<!-- Główna treść -->
6<div role="main">Główna zawartość</div>
7<!-- Lepiej: <main> -->
8
9<!-- Przycisk -->
10<div role="button" tabindex="0">Kliknij</div>
11<!-- Lepiej: <button> -->
12
13<!-- Alert -->
14<div role="alert">Błąd! Wypełnij wszystkie pola.</div>
15
16<!-- Baner (header strony) -->
17<div role="banner">Logo i nawigacja</div>
18<!-- Lepiej: <header> -->
19
20<!-- Informacje dodatkowe -->
21<div role="complementary">Sidebar</div>
22<!-- Lepiej: <aside> -->
23
24<!-- Treść artykułu -->
25<div role="article">Post na blogu</div>
26<!-- Lepiej: <article> -->
27
28<!-- Wyszukiwarka -->
29<div role="search">
30  <form>
31    <input type="search" aria-label="Szukaj w serwisie">
32    <button>Szukaj</button>
33  </form>
34</div>
35
36<!-- Tab panel -->
37<div role="tabpanel" aria-labelledby="tab1">
38  Zawartość zakładki 1
39</div>

UWAGA: Jeśli używasz role na divie, musisz też zadbać o:

  • Nawigację klawiaturą (
    tabindex
    )
  • Obsługę zdarzeń (Enter, Space dla przycisków)
  • Stany (aria-pressed, aria-expanded)

aria-label - dodanie etykiety

aria-label
dodaje tekstowy opis elementu, który jest czytany przez czytniki ekranu:

1<!-- Ikona bez tekstu -->
2<button aria-label="Zamknij okno">
3  <svg><!-- Ikona X --></svg>
4</button>
5
6<!-- Link do social media -->
7<a href="https://facebook.com" aria-label="Odwiedź nas na Facebooku">
8  <img src="fb-icon.svg" alt="">
9</a>
10
11<!-- Wyszukiwarka -->
12<input
13  type="search"
14  aria-label="Wyszukaj produkty w sklepie"
15  placeholder="Szukaj...">
16
17<!-- Przycisk hamburger menu -->
18<button
19  class="hamburger"
20  aria-label="Otwórz menu nawigacyjne"
21  aria-expanded="false">
22  <span></span>
23  <span></span>
24  <span></span>
25</button>
26
27<!-- Nawigacja stronnicowania -->
28<nav aria-label="Nawigacja między stronami">
29  <a href="?page=1">1</a>
30  <a href="?page=2" aria-current="page">2</a>
31  <a href="?page=3">3</a>
32</nav>

Kiedy używać aria-label:

  • ✅ Element ma tylko ikonę (brak tekstu)
  • ✅ Widoczny tekst jest niejasny lub niepełny
  • ✅ Kontekst nie jest oczywisty

Kiedy NIE używać aria-label:

  • ❌ Element ma już jasny, widoczny tekst
  • ❌ Możesz użyć
    <label>
    w formularzu
  • ❌ Obrazek ma już odpowiedni
    alt

aria-labelledby - powiązanie z istniejącą etykietą

aria-labelledby
łączy element z innym elementem, który służy jako etykieta:

1<!-- Modal dialog -->
2<div role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-desc">
3  <h2 id="dialog-title">Potwierdź usunięcie</h2>
4  <p id="dialog-desc">Czy na pewno chcesz usunąć ten element? Tej operacji nie można cofnąć.</p>
5  <button>Usuń</button>
6  <button>Anuluj</button>
7</div>
8
9<!-- Tabs -->
10<div role="tablist">
11  <button role="tab" id="tab1" aria-controls="panel1">Opis</button>
12  <button role="tab" id="tab2" aria-controls="panel2">Specyfikacja</button>
13</div>
14
15<div role="tabpanel" id="panel1" aria-labelledby="tab1">
16  Szczegółowy opis produktu...
17</div>
18
19<div role="tabpanel" id="panel2" aria-labelledby="tab2">
20  Specyfikacja techniczna...
21</div>
22
23<!-- Sekcja z nagłówkiem -->
24<section aria-labelledby="section-heading">
25  <h2 id="section-heading">Najnowsze artykuły</h2>
26  <article>...</article>
27  <article>...</article>
28</section>

aria-describedby - dodatkowy opis

aria-describedby
dodaje rozszerzony opis elementu:

1<!-- Pole formularza z pomocą -->
2<label for="password">Hasło</label>
3<input
4  type="password"
5  id="password"
6  aria-describedby="password-requirements">
7<p id="password-requirements">
8  Hasło musi zawierać minimum 8 znaków, w tym wielką literę i cyfrę.
9</p>
10
11<!-- Przycisk z dodatkowym kontekstem -->
12<button aria-describedby="delete-warning">
13  Usuń konto
14</button>
15<p id="delete-warning">
16  Ta akcja jest nieodwracalna i usunie wszystkie Twoje dane.
17</p>
18
19<!-- Tooltip -->
20<button aria-describedby="tooltip1">
21  Zapisz
22</button>
23<span id="tooltip1" role="tooltip" hidden>
24  Zapisz zmiany w dokumencie (Ctrl+S)
25</span>

Znaczenie atrybutu alt w obrazkach

Atrybut

alt
to jeden z najważniejszych elementów dostępności. Opisuje obrazek dla osób, które go nie widzą.

Dobre praktyki dla alt

1<!-- ✅ DOBRE - opisowy alt -->
2<img
3  src="pyramids-giza.jpg"
4  alt="Trzy piramidy w Gizie o zachodzie słońca, z wielbłądami na pierwszym planie">
5
6<!-- ✅ DOBRE - funkcjonalny alt dla linku -->
7<a href="/products">
8  <img src="shop-icon.svg" alt="Przejdź do sklepu">
9</a>
10
11<!-- ✅ DOBRE - pusty alt dla obrazków dekoracyjnych -->
12<img src="decorative-line.svg" alt="">
13
14<!-- ❌ ZŁE - alt identyczny jak nazwa pliku -->
15<img src="img_001.jpg" alt="img_001">
16
17<!-- ❌ ZŁE - niepotrzebne "zdjęcie", "obrazek" -->
18<img src="cat.jpg" alt="Zdjęcie przedstawiające kota">
19<!-- Lepiej: alt="Kot śpiący na kanapie" -->
20
21<!-- ❌ ZŁE - brak alt -->
22<img src="important-chart.jpg">
23<!-- Czytnik ekranu przeczyta nazwę pliku! -->

Zasady pisania dobrych alt:

  1. Opisz treść, nie formę ("Kot śpiący" zamiast "Zdjęcie")
  2. Kontekst ma znaczenie - co obrazek wnosi do treści?
  3. Bądź zwięzły - 125-150 znaków max
  4. Dekoracyjne obrazki - użyj pustego
    alt=""
  5. Obrazki tekstowe - przepisz dokładnie tekst
  6. Złożone diagramy - użyj również
    aria-describedby
    lub
    <figcaption>
1<!-- Obrazek dekoracyjny (CSS background byłby lepszy) -->
2<img src="divider.svg" alt="">
3
4<!-- Obrazek z tekstem -->
5<img src="sale-banner.jpg" alt="Wyprzedaż 50% - tylko dziś!">
6
7<!-- Złożony wykres -->
8<figure>
9  <img
10    src="sales-chart.jpg"
11    alt="Wykres sprzedaży 2024"
12    aria-describedby="chart-description">
13  <figcaption id="chart-description">
14    Wykres pokazuje wzrost sprzedaży z 10 000 w styczniu do 50 000 w grudniu 2024.
15    Największy skok nastąpił w listopadzie podczas Black Friday.
16  </figcaption>
17</figure>

Przykład: dostępny vs niedostępny komponent

❌ Niedostępny przycisk

1<div class="button" onclick="submitForm()">
2  <img src="send-icon.svg">
3</div>
4
5<style>
6.button {
7  background: blue;
8  padding: 10px;
9  cursor: pointer;
10}
11</style>

Problemy:

  • Nie ma semantyki (div zamiast button)
  • Nie działa z klawiatury (Tab, Enter)
  • Brak tekstowego opisu (tylko ikona)
  • Czytnik ekranu nie wie, że to przycisk

✅ Dostępny przycisk

1<button
2  type="submit"
3  aria-label="Wyślij formularz">
4  <img src="send-icon.svg" alt="">
5</button>
6
7<style>
8button {
9  background: blue;
10  padding: 10px;
11  cursor: pointer;
12  border: none;
13  color: white;
14}
15
16button:focus {
17  outline: 3px solid orange;
18  outline-offset: 2px;
19}
20</style>

Zalety:

  • ✅ Semantyczny
    <button>
    - automatyczna obsługa klawiatury
  • aria-label
    opisuje funkcję
  • ✅ Focus outline dla użytkowników klawiatury
  • type="submit"
    - jasna funkcja

Jak testować dostępność

1. Lighthouse (Chrome DevTools)

Krok po kroku:

  1. Otwórz DevTools (F12)
  2. Zakładka "Lighthouse"
  3. Zaznacz "Accessibility"
  4. Kliknij "Generate report"

Lighthouse sprawdzi:

  • Kontrast kolorów
  • Atrybuty alt w obrazkach
  • ARIA attributes
  • Hierarchię nagłówków
  • Form labels
  • I wiele więcej...

Wynik: Raport z oceną 0-100 i konkretnymi problemami do naprawienia.

2. Nawigacja klawiaturą

Test ręczny:

  1. Schowaj mysz
  2. Używaj tylko klawiatury:
    • Tab - przejdź do kolejnego elementu
    • Shift+Tab - wróć do poprzedniego
    • Enter - aktywuj link/przycisk
    • Space - zaznacz checkbox, aktywuj przycisk
    • Arrow keys - nawigacja w select, radio buttons
  3. Sprawdź:
    • ✅ Czy widzisz focus outline?
    • ✅ Czy kolejność jest logiczna?
    • ✅ Czy możesz dotrzeć wszędzie?
    • ✅ Czy nie ma "pułapek" na focus?

3. Czytnik ekranu

Windows: NVDA (darmowy) Mac: VoiceOver (wbudowany - Cmd+F5) Chrome: ChromeVox (rozszerzenie)

Podstawowe komendy (NVDA):

  • Ctrl - zatrzymaj czytanie
  • Insert+Down Arrow - czytaj wszystko
  • H - skocz do kolejnego nagłówka
  • K - skocz do kolejnego linku
  • B - skocz do kolejnego przycisku
  • F - skocz do kolejnego pola formularza

4. axe DevTools (rozszerzenie)

Rozszerzenie do Chrome/Firefox, które automatycznie wykrywa problemy z dostępnością:

  • Instalacja: Chrome Web Store → "axe DevTools"
  • Użycie: F12 → zakładka "axe DevTools" → "Scan ALL"

5. WAVE (WebAIM)

Online narzędzie: https://wave.webaim.org/

  • Wprowadź URL strony
  • Otrzymasz wizualną analizę z oznaczonymi błędami

Checklist dostępności

HTML i semantyka:

  • ☐ Używam semantycznych znaczników (
    <header>
    ,
    <nav>
    ,
    <main>
    ,
    <article>
    )
  • ☐ Hierarchia nagłówków jest logiczna (h1 → h2 → h3)
  • ☐ Każda strona ma dokładnie jeden
    <main>

Obrazki:

  • ☐ Wszystkie obrazki mają atrybut
    alt
  • ☐ Obrazki dekoracyjne mają pusty
    alt=""
  • ☐ Alt teksty są opisowe i zwięzłe

Formularze:

  • ☐ Każde pole ma
    <label>
    lub
    aria-label
  • ☐ Błędy walidacji są czytelne i jasne
  • ☐ Wymagane pola są oznaczone (
    required
    lub
    aria-required="true"
    )

Nawigacja klawiaturą:

  • ☐ Mogę dotrzeć wszędzie używając tylko Tab
  • ☐ Focus outline jest widoczny
  • ☐ Kolejność Tab jest logiczna
  • ☐ Interaktywne elementy reagują na Enter/Space

Kolory i kontrast:

  • ☐ Kontrast tekstu to minimum 4.5:1 (normalny tekst)
  • ☐ Kontrast tekstu to minimum 3:1 (duży tekst 18px+)
  • ☐ Informacje nie są przekazywane TYLKO kolorem

ARIA:

  • ☐ ARIA używane tylko gdy semantyczny HTML nie wystarcza
  • role
    są poprawnie użyte
  • ☐ Dynamiczne treści mają
    aria-live
  • ☐ Modals mają
    role="dialog"
    i
    aria-labelledby

Testy:

  • ☐ Lighthouse Accessibility: 90+
  • ☐ Przetestowane czytnikiem ekranu
  • ☐ Przetestowane tylko klawiaturą

Podsumowanie

Semantyczne HTML:

  • Używaj
    <button>
    ,
    <nav>
    ,
    <main>
    ,
    <article>
    zamiast divów
  • Zapewnia automatyczną dostępność
  • Lepsza dla SEO i maintenance

ARIA roles:

  • role="navigation"
    ,
    role="main"
    ,
    role="button"
  • Używaj TYLKO gdy semantyczny HTML nie wystarcza
  • Wymaga dodatkowej obsługi klawiatury i stanów

ARIA labels:

  • aria-label
    - dodaje tekstowy opis
  • aria-labelledby
    - łączy z istniejącym elementem
  • aria-describedby
    - dodaje rozszerzony opis

Alt w obrazkach:

  • Opisuj treść, nie formę
  • Pusty
    alt=""
    dla dekoracji
  • Kontekst ma znaczenie

Testowanie:

  • Lighthouse (DevTools)
  • Nawigacja klawiaturą
  • Czytnik ekranu (NVDA, VoiceOver)
  • axe DevTools
  • WAVE

Pamiętaj: Dostępność to nie dodatkowa funkcja - to fundamentalna część tworzenia stron internetowych. Podobnie jak piramidy w Gizie były budowane dla wszystkich pokoleń, tak strony internetowe powinny być dostępne dla wszystkich użytkowników!

Przejdź do CodeWorlds