O mnieBlogGitHub

Meeting Web Accessibility Guidelines - kurs Pluralsight

10 May, 2020 - 10 min read

Notatki do kursu Pluralsight o dostępności stron internetowych pn. "Meeting Web Accessibility Guidelines (Section 508/ WCAG 2.1)"

Wybór "kodeksu"

Istnieją w branży pewne "kodeksy" (conformance guidelines), określające zasady dostosowania stron internetowych dla osób z niepełnosprawnościami.

Jakie są korzyści z ich zastosowania?

  • dostępność dla OzN
  • zabezpiecza przed pozwami sądowymi (tak, w Stanach firma może być pozwana np. za to, że jej strona nie jest dostępna dla osób niewidomych)
  • poprawa SEO
  • ogólnie lepsze usability
  • kiedy się zestarzejesz, łatwiej Ci będzie z tej aplikacji korzystać - bo z wiekiem i Ty będziesz mieć problemy np. ze wzrokiem

Najbardziej znane "kodeksy" (z perspektywy amerykańskiej):

  • Section 508
  • WCAG 2.1

Section 508

  • uchwalona w 1986 r. poprawka do Rehabilitation Act z 1973 r., zaktualizowana też w 2017 r.
  • dotyczy stron rządowych albo takich, które za rządowe środki powstały
  • w przeciwieństwie do ogólnoświatowego WCAG, Section 508 jest używana głównie w USA

WCAG (Web Conformance Accessiblity Guideline)

  • tworzone przez grupę, która jest częścią W3C (industry standard)
  • oparte na czterech zasadach (POUR):

    • perceivable - każdy użytkownik jest w stanie "odebrać" informację
    • operable - każdy użytkownik jest w stanie operować na stronie, bez względu na to, czy używa myszki, czy klawiatury
    • understandable - informacja na stronie jest zrozumiała, a interakcje przewidywalne (logiczne)
    • robust - strona musi działać z różnymi technologiami asystującymi
  • poziomy: A, AA, AAA (im więcej A, tym bardziej "restrykcyjne" reguły)
  • strona WCAG zawiera dokładnie rozpisanie kilkudziesięciu wskazówek
  • podstawowa rekomendacja - osiągnąć WCAG 2.1 AA (co przy okazji wypełnia w 100% Section 508)

HTML

Struktura strony

  • ściśle poprawny HTML:

    • <!doctype html> - wymagane przez WCAG!
    • brak zduplikowanych albo niedomkniętych tagów
  • określić język strony (WCAG A 3.1.1) - atrybut lang na elemencie <html>; jeśli jakieś fragmenty są w innym języku - nawet kawałki span - tam też należy użyć atrybutu lang, żeby zmienić "lokalnie" język (WCAG AA 3.1.2)
  • tytuł strony (WCAG A 2.4.2), inny dla każdej strony (żeby ułatwić orientację)
  • poprawne skalowanie (WCAG AA 1.4.4):

    • <meta name="viewport"> - nie stosować user-scalable=no ani maximum-scale=1 (bo to wyłącza powiększenie)
    • używaj w CSS relative units, tzn. rem lub em do określania rozmiarów (bo WCAG AA 1.4.1 wymaga, żeby dało się korzystać ze strony powiększonej o 200%)
    • strona musi działać i wyglądać, nawet jeśli użytkownik powiększy interlinię (do 1.5), odstęp po akapicie (do 2-krotności czcionki), kerning (do 1/8 rozmiaru czcionki) lub odstęp między wyrazami (do 1/6 rozmariu czcionki) - WCAG AA 1.4.12
  • używaj tagów z HTML5, tj. header, nav, main, footer, aside (WCAG A 1.3.1, WCAG A 2.4.1) - bo ujawniają strukturę treści oraz ułatwiają nawigację

    • jeśli jest kilka elementów nav na stronie - np. na górze, powtórka w stopce oraz oddzielny na bocznym pasku, to mozna je odróżnić nazwami, podanymi w atrybucie aria-label
    • main może być tylko jeden na stronie
  • używaj nagłówków (WCAG A 2.4.6)

    • h1 może być tylko jeden na stronie
    • nagłówki powinny iść po kolei, bez przeskakiwania, np. z h1 od razu do h5
  • stosuj listy (li, ul) zamiast grupy div-ów - screen reader dzięki temu może rozpoznać, jaki to jest typ listy, ile ona zawiera elementów oraz poinformować, który element z listy jest aktywny (WCAG A 1.3.1)

Nawigacja

  • użyj tekstu zamiast obrazka z tekstem, np. w linkach (WCAG AA 1.4.5)
  • linki nawigacyjne na różnych stronach poiwnny być w tej samej kolejności na wszystkich stronach (WCAG AA 3.2.3)
  • spójna identyfikacja - jeśli na stronie jest np. wyszukiwarka na pasku, to przycisk "submit" powinien być wszędzie opisany tak samo (WCAG AA 3.2.4)
  • linki powinny opisywać to, dokąd prowadzą - nie używaj czegoś w stylu: <p>Kliknij <a>tutaj</a>, żeby złożyć zamówienie</p> (WCAG A 2.4.4)

    • unikaj samego "czytaj więcej" w opisie linku - jeśli użytkownik będzie iterował po samych linkach, to będzie miał tylko listę wielu "czytaj więcej" (np. na stronie głównej bloga) i nie będzie wiedział, dokąd one prowadzą; pewnym kompromisem jest mieć coś takiego:

      <a href="/strona">
      Czytaj więcej <span class="hidden">o nowościach w .NET</span>
      </a>

      wówczas wystarczy dopowiednio ostylować CSS-ową klasę hidden tak, aby była niewiodczna - czytnik ekranu jednak ten tekst odczyta

  • bypass blocks (WCAG A 2.4.1) - czyli mechanizm do omijania np. nagłówka z linkami; taki skip link powinien:

    • być pierwszym elementem na stronie
    • ostylowany tak, aby występował poza ekranem, chyba, że jest na nim fokus, np. tak:
    .skip-link {
    left: -100%;
    position: absolute;
    }
    
    .skip-link:focus {
    left: 50%;
    }
    • jeśli robimy "skok" robimy za pomocą fokusa, to:
    • docelowy element (ten, do którego skip link ma nawigować) powienien mieć atrybut tabindex ustawiony na -1
    • na onclick tego skip linka, powinniśmy sfokusować docelowy element

Tabele

Table should not be used for layout! It is not 1999.

  • tytuł tabeli, poprzedzający ją, powienien być w tagu caption (pierwszy "child" elementu table)
  • nagłówek: użyj th zamiast td i użyj atrybutu scope="col" (bo tam jest "tytuł" dla kolumny)
  • wiersz: jeśli w tabeli są grupy (wiersza z colspan, będące nagłówkami grupy), to to tam użyj th, ale scope="colgroup"
  • jeśli nadasz nagłówkom th (dla kolumn i grup) unikalne identyfikatory, możesz ich użyć w komórkach td atrybutu headers z wartością będącą listą id-ków nagłówków (coś w stylu współrzędnych)
  • za pomocą ukrywania CSS-em (tak jak było to z "read more") możesz w tagu caption dać szerszy opis, jak dane są ustrykturyzowane, zwłaszcza jeśli tabela jest bardziej złożona, ma podgrupy itp.
  • dzięki strukturze tabeli (zamiast div-ów) VoiceOver będzie poprawnie opisywał komórki oraz umożliwi nawigację pomiędzy wierszami/kolumnami za pomocą skrótów klawiszowych
  • ogólnie lepiej złożone tabele rozbijać na kilka mniejszych, bo to ułatwi zadanie czytnikowi ekranu
  • tag tfoot powinen być przed tagiem tbody

Formularze

  • odpowiednie opisy i etykiety do pól (WCAG A 1.3.1, WCAG A 3.3.2, WCAG AA 2.4.6)
  • na inputach label musi się zgadzać z widocznym opisem pola (WCAG A 2.5.3)
  • zgrupuj pola, które dotyczą logicznej całości (np. kilka inputów dla adresu: miasto, ulica etc.) - używaj fieldset, legend
  • walidacja, stan pola itp. nie mogą być wyróżnione tylko w sposób wizualny (WCAG 1.3.3)
  • jeśli input jest niestandardowy, zadbaj o to, by się poprawnie fokusował, inaczej osoba korzystająca tylko z klawiatury, nie będzie w stanie "doscrollować się" do niego i go zobaczyć (WCAG A 2.1.1)
  • no keyboard traps (WCAG A 2.1.2)
  • jeśli obiekt jest fokusowalny, to stan focus i zwykły muszą być wizualnie rozróżnialne (AA 2.4.7)
  • błędy muszą być opisane tekstem (a nie tylko np. obrazkiem wykrzyknika) - WCAG A 3.3.; jeśli jest możliwe zasugerować, jak poprawić błąd (np. data podróży "tam" nie może być późniejsza niż podróż powrotna), to powinno być to przedstawione użytkownikowi (WCAG AA 3.3.3)
  • element form powinien mieć atrybut novalidate, bo przeglądarkowe "tooltipy" takiej walidacji nie są dostępne
  • label: albo za pomocą atrybutu for (wtedy label jest rodzeństwem opisywanego inputu), albo poprzez opakowanie (wówczas label jest rodzicem)
  • tabindex - dwie dozwolone wartości: -1 (wyłączamy z naturalnej kolejności focusowania, ale możemy sfocusować za pomocą JS) oraz 0 (po prostu zmienia element niefokusowalny w fokusowalny)
  • jeśli formularz ma konsekwencje w "realnym życiu" (np. zakup) albo w bazie danych (np. zapis edytowanego rekordu), końcowa akcja musi być zatwierdzana (WCAG AA 3.3.4)
  • jeśli istnieje jakiś limit czasowy (np. automatyczne zakończenie sesji), użytkownik musi mieć co najmniej 20 sekund na podjęcie decyzji, czy chce przesunąć ten limit czasowy (WCAG A 2.2.1); oczywiście to nie dotyczy tych ograniczeń czasowych, które wynikają z "reguł biznesowych", np. ograniczonej w czasie rezerwacji miejsca podczas zakupu biletu
  • kontrast dla tekstu powinien być co najmniej 4,5:1 (WCAG AA 1.4.3)
  • elementy interfejsu i grafiki powinny mieć kontrast co najmniej 3:1 (WCAG 1.4.11)

Obrazy, dźwięki i filmy

Obrazy

  • nie wolno używać obrazków z tekstem zamiast zwykłego tekstu (WCAG AA 1.4.5)
  • podstawowa zasada - WCAG A 1.1.1 - nietekstowe treści powinny być zaprezentowane w jakiejś alternatywnej, tekstowej formie
  • wszystkie obrazki powinny mieć atrybut alt; jeśli dany obrazek jest tylko dekoracją, to powinny mieć pusty atrybut alt (inaczej czytnik ekranu będzie czytał nazwę pliku...)

    • opis w atrybucie alt wcale nie musi być literalnym opisem tego, co jest na obrazku
    • nie używaj fraz typu "obrazek przedstawia...", bo czytnik ekranu już sam informuje, że dany element jest obrazem
    • opisz znaczenie lub cel obrazu, a jeśli zawiera tekst, który ma znaczenie, to powinien on być też w atrybucie alt
  • jeśli obraz jest ustawiony jako tło w CSS (częsty przykład z ikonami, robiony po to, by poprawić wydajność strony), należy po prostu dodać ukryty tekst, który opisuje ikonę (skoro nie ma tagu img, nie możemy użyć alt)
  • obrazek wektorowy (SVG) - należy dodać:

    • role="img", żeby czytnik ekranu wiedział, że to jest obrazek
    • wewnątrz tagu svg - tag title; opcjonalnie, jeśli chcemy szerzej opisać obrazek, można dodać też tag desc
    • żeby zapewnić kompatybilność z różnymi przeglądarkami, należy za pomocą aria-labelledby zrobić odnośnik do tagu title (i analogicznie atrybutem aria-describedby, jeśli używamy tagu desc)

Dźwięk

  • każde nagranie audio, które nie jest "na żywo" (i.e. zostało nagrane wcześniej) powinno mieć reprezentację tekstową, która prezentuje tę samą treść (transkrypcję) - WCAG A 1.2.1

    • Google Docs Voice Typing albo Windows Speech Recognition - narzędzia, które mogą zapewnić półautomatyczną transkrypcję (pewnie tylko lub głównie po angielsku...)
    • w transkrypcji podaj imiona (nazwiska) rozmawiających oraz opisz też "pozawerbalne" dźwięki (śmiech, inny ton)
  • jeśli na stronie automatycznie włącza się jakiś dźwięk na dłużej niż 3 sekundy, musi być mechanizm, żeby ten dźwięk wyłączyć lub zapauzować lub dostosować jego głośność niezależnie od poziomu głośności urządzenia (WCAG A 1.4.2) - (na marginesie: ja bym tu też dodał: Żadna strona nie powinna na dzień dobry atakować użytkownika dźwiękami. Nie jesteśmy w roku 1999. ;) )
  • analogicznie, jeśli jakaś treść, która się automatycznie przesuwa, zmienia lub pulsuje (czyli nie tylko filmy, ale np. "karuzele") - musi być mechanizm, żeby taką treść zatrzymać lub ukryć (WCAG A 2.2.2)
  • jeśli cokolwiek błyska/pulsuje, minimalna częstotliwość to 3 Hz - chodzi o uniknięcie napadów epilepsji (inna sprawa, że migające strony to znowu wygląda jak rok 1999...)

Filmy

  • po pierwsze - transkrypcja wypowiedzi (tak, jakby to było samo audio)
  • po drugie: napisy do filmu; WCAG A 1.2.1 wymaga tylko dla filmów uprzednio nagranych, natomiast WCAG AA 1.2.4 - także dla nagrań na żywo

    • dwa rodzaje:
    • "open" - zawsze widoczne, "wgrane" do filmu
    • "closed" - pokazywane tylko na życzenie użytkownika, jako nakładka na film
  • po trzecie: audiodeskrypcja (słowny opis tego, co widać i co się dzieje na filmie oraz odłgosów lub muzyki, budującej nastrój) - WCAG AA 1.2.5

Responsive Web Design

Visual order must match DOM order

Czyli kolejność fokusów musi być sensowna i taka, jak to jest widoczne, bez przeskakiwania np. do stopki, żeby potem wrócić do głównej treści (WCAG A 1.3.2, WCAG A 2.4.3).

  • strona musi działać niezależnie, jak obrócony jest telefon (portret/krajobraz) - WCAG AA 1.3.4
  • jeśli operacja jest dostępna za pomocą gestów (np. zoom dwoma palcami), to musi być też ścieżka za pomocą pojdenyczego wskazania (np. przyciski +/-) (WCAG A 2.5.1)
  • akcje powinny być podpięte pod eventy typu click/touch, a nie pod keydown/touchdown - tak aby można było wycofać się z akcji poprzez przesunięcie się (myszką, palcem) poza element (WCAG A 2.5.2)
  • jeśli operacja jest wyzwalana poruszaniem urządzenia, powinna być też opcja, żeby wykonać ją za pomocą "zwykłego" UI (WCAG A 2.5.4)
  • jak ukryć element?

    • display: none lub visibility:hidden w CSS-ie - niewidoczy dla wzorku, ale i czytnika ekranu
    • aria-hidden="true" - ukrywa tylko przed czytnikiem ekranu
    • wypozycjonowanie poza ekran - niewidoczny dla wzroku, ale widoczny dla czytnika - np. takim CSS-em:

      .hidden {
      position: absolute;
      left: -10000px;
      top: auto;
      width: 1px;
      height: 1px;
      overflow: hidden;
      }
© 2020, Built with Gatsby