Pet pravil ARIA, ki jih večina prekrši

ARIA lahko naredi napredne spletne komponente razumljive uporabnikom podpornih tehnologij. Lahko pa doseže tudi nasprotno: pravilno delujoč vmesnik predstavi kot nekaj, kar v resnici ni.

Težava zato običajno ni v pomanjkanju atributov ARIA, temveč v njihovi nepravilni uporabi.

ARIA oziroma Accessible Rich Internet Applications omogoča, da elementom določimo dostopne vloge, stanja, lastnosti in medsebojne odnose. Brskalnik te informacije posreduje podporni tehnologiji, na primer bralniku zaslona.

ARIA pa ne spremeni dejanskega vedenja elementa. Ne doda upravljanja s tipkovnico, ne premakne fokusa, ne odpre menija in ne izvede preverjanja obrazca. Opisuje predvsem, kako naj podporna tehnologija razume uporabniški vmesnik.

Prav zato je napačno uporabljena ARIA lahko nevarnejša od manjkajoče. Uporabniku namreč ne posreduje premalo informacij, ampak napačne informacije. W3C to načelo povzema zelo neposredno: slaba ARIA je pogosto slabša kot nobena ARIA.

ARIA je kot pogodba s podpornimi tehnologijami. Z njo obljubimo, da ima element določeno vlogo, ime, stanje in pričakovani način interakcije. Ker ARIA sama ne zagotovi vedenja elementa, moramo pri komponentah po meri s HTML-jem in JavaScriptom zagotoviti tudi interaktivnost, upravljanje fokusa ter sprotno posodabljanje stanj.

Najprej semantični HTML, šele nato ARIA

Preden elementu dodamo vlogo ali atribut ARIA, se moramo vprašati, ali HTML že ponuja element ali atribut z ustreznim pomenom in pričakovanim vedenjem.

Prvo pravilo uporabe ARIA je: uporabimo izvorni element HTML, kadar ta že zagotavlja semantiko in funkcionalnost, ki ju potrebujemo.

To na primer pomeni, da uporabimo:

  • <button> za aktivacijo dejanja,
  • <a href="..."> za povezavo na drugo stran ali lokacijo,
  • <nav> za glavno ali drugo pomembno navigacijo,
  • <h1><h6> za naslove,
  • <fieldset> in <legend> za smiselno skupino obrazčnih polj.

Takšni elementi imajo že vgrajeno semantiko, praviloma pa tudi pričakovano vedenje brskalnika in bolj dosledno podporo v podpornih tehnologijah.

Slabša rešitev:

<!-- Semantiko in vedenje moramo zagotoviti sami. -->
<div role="button" tabindex="0">Shrani</div>

Boljša rešitev:

<!-- Semantika in osnovno vedenje sta že vgrajena. -->
<button type="button">Shrani</button>

Najprej torej izberemo pravi element HTML. ARIA naj obstoječo semantiko dopolni, nadomesti pa jo le takrat, ko HTML za zahtevano rešitev nima ustreznega mehanizma.

Po atributih ARIA posežemo, kadar HTML ne ponuja potrebne semantike, stanja ali odnosa. Smiselni primeri so:

  • aria-expanded na izvornem gumbu, ki odpira in zapira vsebino,
  • aria-pressed za stanje preklopnega gumba,
  • aria-describedby za povezavo elementa z dodatnim opisom,
  • živa območja za pomembne dinamične spremembe, ki jih uporabnik sicer ne bi zaznal.

Pri kompleksnih komponentah po meri ARIA določi način predstavitve, razvijalec pa mora še vedno zagotoviti ustrezno vedenje, upravljanje s tipkovnico, fokus in usklajevanje stanj.

1. Vloga je obljuba, ne dekoracija

Atribut role ni opis videza elementa. Je obljuba o njegovem pomenu in pričakovanem vedenju.

Ko elementu določimo vlogo gumba, podporni tehnologiji sporočimo, da gre za gumb. Uporabnik zato pričakuje, da ga bo mogoče doseči s tipkovnico, aktivirati na običajen način in da bodo pravilno predstavljena njegova morebitna stanja.

Toda role="button" sam po sebi ne zagotovi ničesar od tega. ARIA ne doda možnosti fokusa, odziva na tipke ali privzetega vedenja gumba.

<div role="button">
  Oddaj naročilo
</div>

Element v tem primeru podporni tehnologiji predstavimo kot gumb, vendar brez dodatne implementacije ni dosegljiv s tipko Tab in se ne odziva na tipki Enter ter Preslednica, kot bi se moral pravi gumb.

Enako velja za zahtevnejše vloge, kot so menu, listbox, tablist, tree, grid in dialog. Vsaka ima pričakovano notranjo strukturo, dovoljene ali zahtevane atribute ARIA in določen način upravljanja s tipkovnico.

Vloge ne izberemo glede na to, kako je element videti, ampak glede na to, kaj element dejansko je in kako deluje.

2. aria-label ni univerzalni obliž

Ena najpogostejših napačnih predstav je, da lahko dostopnost elementa izboljšamo tako, da mu preprosto dodamo aria-label.

aria-label ne dodaja dodatnega pojasnila, ampak elementu določi dostopno ime. Pri številnih elementih in vlogah s tem nadomesti ime, ki bi ga brskalnik sicer izračunal iz vidne vsebine.

<button aria-label="Izbriši">
  Odstrani fotografijo
</button>

V tem primeru videči uporabnik prebere »Odstrani fotografijo«, uporabnik podporne tehnologije pa lahko prejme samo ime »Izbriši«. Vidno in dostopno ime se razlikujeta, kar lahko povzroči zmedo in težave predvsem uporabnikom glasovnega upravljanja.

Če je vidno besedilo ustrezno, dodatni aria-label praviloma ni potreben:

<button type="button">
  Odstrani fotografijo
</button>

aria-label je smiseln predvsem takrat, ko ustreznega vidnega besedila ni, na primer pri gumbu, ki vsebuje samo ikono:

<button type="button" aria-label="Odstrani fotografijo">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
    <!-- Ikona koša -->
  </svg>
</button>

aria-label uporabimo šele, ko element nima ustreznega vidnega imena in razumemo, kateri obstoječi vir dostopnega imena bomo z njim prepisali.

3. Stanja ARIA morajo vedno govoriti resnico

ARIA ni samo začetna konfiguracija komponente. Pri dinamičnem vmesniku mora ves čas odražati njegovo trenutno stanje.

Dokler je plošča s filtri zaprta, je aria-expanded="false" pravilen podatek:

<button
  type="button"
  aria-expanded="false"
  aria-controls="filter-panel"
>
  Filtri
</button>

<div id="filter-panel" hidden>
  <!-- Vsebina filtrov -->
</div>

Ko se plošča odpre, moramo hkrati odstraniti atribut hidden in vrednost aria-expanded spremeniti v true.

Če se vsebina vizualno odpre, atribut pa ostane nastavljen na false, podporna tehnologija uporabniku sporoči nasprotno od tega, kar se je dejansko zgodilo.

Enako načelo velja za:

  • aria-pressed,
  • aria-selected,
  • aria-checked,
  • aria-current,
  • aria-invalid,
  • aria-busy.

Ti atributi niso sopomenke, čeprav lahko njihova stanja povzročijo podoben vizualni rezultat. Vsak ima svoj semantični pomen in se uporablja v določenem kontekstu.

Vizualno stanje, funkcionalno stanje in stanje ARIA morajo biti usklajeni v vsakem trenutku.

4. aria-hidden ne pomeni »skrij element«

Atribut aria-hidden="true" element in njegove potomce odstrani iz drevesa dostopnosti. Namenjen je skrivanju vsebine pred podpornimi tehnologijami, ne splošnemu skrivanju elementa.

Za skrivanje elementa pred vsemi uporabniki praviloma uporabimo atribut hidden ali ustrezno pravilo CSS, na primer display: none.

Primer napačne uporabe:

<div aria-hidden="true">
  <button type="button">Potrdi naročilo</button>
</div>

Gumb je lahko še vedno prisoten na strani in dosegljiv s tipkovnico, njegov nadrejeni element pa je izključen iz drevesa dostopnosti. Uporabnik lahko tako fokus premakne na interaktivni element, ki ga podporna tehnologija ne predstavi pravilno ali ga sploh ne predstavi.

aria-hidden velja tudi za vse potomce. Če je nastavljen na nadrejenem elementu, potomca ni mogoče ponovno smiselno izpostaviti samo z uporabo aria-hidden="false".

Ustrezna uporaba je na primer dekorativna ikona, katere pomen je že podan z vidnim besedilom:

<button type="button">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
    <!-- Dekorativna ikona -->
  </svg>
  Prenesi dokument
</button>

Elementa z atributom aria-hidden="true" ne uporabljamo kot nadrejenega elementa interaktivnih kontrol.

Pred uporabo se vprašajmo: ali je ta vsebina za uporabnika podporne tehnologije res odvečna ali jo skrivamo samo zato, ker nam povzroča težave?

5. aria-live ni zvočnik za vsako spremembo

Dinamične spremembe vsebine so lahko za uporabnika bralnika zaslona neopazne. aria-live omogoča, da je uporabnik obveščen o pomembni spremembi, ne da bi moral sam premakniti fokus.

Vrednost polite pomeni, da naj se posodobitev praviloma napove ob naslednji primerni priložnosti. Počaka torej, da bralnik zaslona konča trenutno najavo.

<div aria-live="polite"></div>

Vrednost assertive lahko trenutno govorjeno vsebino prekine, zato je primerna samo za res nujna in časovno občutljiva sporočila.

<div aria-live="assertive"></div>

Težava nastane, ko razvijalec z aria-live označi celoten obrazec, celoten seznam rezultatov, glavni vsebinski del strani ali območje z zelo pogostimi spremembami. Posledica so lahko dolge, ponavljajoče se ali prekinjajoče najave.

Za običajna potrditvena in informativna sporočila je pogosto primerna vloga status, ki ima privzeto vedenje, primerljivo z aria-live="polite":

<div role="status">
  Izdelek je bil dodan v košarico.
</div>

Za pomembno in časovno občutljivo opozorilo je namenjena vloga alert, ki ima privzeto vedenje, primerljivo z aria-live="assertive":

<div role="alert">
  Seje bo konec čez eno minuto.
</div>

Napovemo samo spremembo, ki jo mora uporabnik poznati, da lahko razume rezultat dejanja ali nadaljuje postopek. Sporočilo naj bo kratko in jasno.

ARIA mora vmesnik opisovati, ne pa ga nadomeščati

Kakovosti implementacije ARIA ne moremo oceniti s štetjem atributov. Več atributov ne pomeni bolj dostopnega vmesnika. Pogosto lahko pomeni ravno nasprotno.

Dobra implementacija mora uporabniku posredovati štiri točne informacije:

Kaj je element?
To določa njegova vloga.
Kako se imenuje?
To določa njegovo dostopno ime. Najboljša možnost je praviloma ustrezno vidno besedilo, po potrebi pa lahko uporabimo aria-labelledby ali aria-label.
V kakšnem stanju je?
To določajo atributi, kot so aria-expanded, aria-selected ali aria-pressed.
S čim je povezan?
Odnose lahko med drugim določimo z atributi aria-labelledby, aria-describedby in v ustreznih primerih aria-controls.

Če je katera od teh informacij napačna, podporna tehnologija ne dobi samo slabše različice vidnega vmesnika, ampak drugačen vmesnik: z drugačnimi imeni, drugačnimi stanji in drugačnimi pričakovanji.

Poimenovanje z aria-labelledby

Kadar je ustrezno besedilo že vidno na strani, ga lahko uporabimo kot dostopno ime drugega elementa:

<h3 id="search-title">Iskanje</h3>

<input
  type="search"
  aria-labelledby="search-title"
>

Povezava polja z opisom napake

Z atributom aria-describedby lahko obrazčno polje povežemo z dodatnim opisom ali sporočilom o napaki:

<label for="user-id">
  ID v obliki xxx-yyyy
</label>

<input
  type="text"
  id="user-id"
  aria-invalid="true"
  aria-describedby="user-id-error"
>

<p id="user-id-error">
  ID je neveljaven. Uporabite obliko xxx-yyyy.
</p>

Najboljša ARIA je primerna in natančna

Preden dodamo atribut ARIA, si zastavimo tri vprašanja:

  1. Ali uporabniku sporoča resničen podatek?
  2. Ali je ta podatek za uporabnika potreben?
  3. Ali podatek odraža trenutno stanje vmesnika?

Če odgovor ni jasen, atribut verjetno ne sodi v kodo. Najboljša ARIA ni tista, ki je najbolj obsežna. Najboljša je tista, ki je primerna, natančna in ves čas usklajena z dejanskim vedenjem vmesnika.