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
langna elemencie<html>; jeśli jakieś fragmenty są w innym języku - nawet kawałkispan- tam też należy użyć atrybutulang, ż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=noanimaximum-scale=1(bo to wyłącza powiększenie)- używaj w CSS relative units, tzn.
remlubemdo 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
navna stronie - np. na górze, powtórka w stopce oraz oddzielny na bocznym pasku, to mozna je odróżnić nazwami, podanymi w atrybuciearia-label mainmoże być tylko jeden na stronie
- jeśli jest kilka elementów
- używaj nagłówków (WCAG A 2.4.6)
h1może być tylko jeden na stronie- nagłówki powinny iść po kolei, bez przeskakiwania, np. z
h1od razu doh5
- stosuj listy (
li,ul) zamiast grupydiv-ó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ę
hiddentak, 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
onclicktego skip linka, powinniśmy sfokusować docelowy element
- docelowy element (ten, do którego skip link ma nawigować) powienien mieć atrybut tabindex ustawiony na
Tabele
Table should not be used for layout! It is not 1999.
- tytuł tabeli, poprzedzający ją, powienien być w tagu
caption(pierwszy “child” elementutable) - nagłówek: użyj
thzamiasttdi użyj atrybutuscope="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żyjth, alescope="colgroup" - jeśli nadasz nagłówkom
th(dla kolumn i grup) unikalne identyfikatory, możesz ich użyć w komórkachtdatrybutuheadersz 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
captiondać 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
tfootpowinen być przed tagiemtbody
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
formpowinien mieć atrybutnovalidate, bo przeglądarkowe “tooltipy” takiej walidacji nie są dostępne label: albo za pomocą atrybutufor(wtedylabeljest rodzeństwem opisywanego inputu), albo poprzez opakowanie (wówczaslabeljest rodzicem)tabindex- dwie dozwolone wartości:-1(wyłączamy z naturalnej kolejności focusowania, ale możemy sfocusować za pomocą JS) oraz0(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 atrybutalt(inaczej czytnik ekranu będzie czytał nazwę pliku…)- opis w atrybucie
altwcale 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
- opis w atrybucie
-
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- tagtitle; opcjonalnie, jeśli chcemy szerzej opisać obrazek, można dodać też tagdesc - żeby zapewnić kompatybilność z różnymi przeglądarkami, należy za pomocą
aria-labelledbyzrobić odnośnik do tagutitle(i analogicznie atrybutemaria-describedby, jeśli używamy tagudesc)
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
- dwa rodzaje:
- 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 podkeydown/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: nonelubvisibility:hiddenw CSS-ie - niewidoczy dla wzorku, ale i czytnika ekranuaria-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; }