ARIA jako CSS nástroj

Specifikace ARIA vznikla pro zpřístupnění webu postiženým uživatelům, kteří jsou odkázáni na různá zařízení jako jsou čtečky textu (text-to-speech), braillovo displeje či speciální ovládací joysticky nebo klávesnice.

ARIA = Accessible Rich Internet Application (Přístupná webová aplikace)

Specifikace ale obsahuje celou řadu rolí a vlastností, které můžete přiřazovat prvkům v HTML, můžete se na ně v CSS odkazovat přes selektor vlastnosti a v Javaskriptu je používat pro ukládání stavu prvků. Navíc WAI-ARIA je již součástí HTML5 specifikace, takže uvedením <!DOCTYPE html> je ARIA automaticky zahrnuto ve stránce (pro HTML4 bylo potřeba uvést správné DTD).

Třída vs. ARIA

Pokud v HTML označíte prvky jejich zamýšlenou funkcí:

&amp;amp;amp;lt;a role=button href="/"&amp;amp;amp;gt;Zpět&amp;amp;amp;lt;/a&amp;amp;amp;gt;
&amp;amp;amp;lt;img role=link onclick="zoom(this)" src="img.png"&amp;amp;amp;gt;

Můžete je pak v CSS správně naformátovat:

*[role=button] { border: 1px solid gray; ... }
*[role=link] { color: blue; ... }

Když pro změnu funkce a vzhledu použijete třídy, nic to neznamená a kdokoliv může stejnou třídu použít pro něco jiného a pak (ve větším projektu s více lidmi) řešíte kolize javascriptu a CSS.


&amp;amp;amp;lt;div class="form"&amp;amp;amp;gt;
    &amp;amp;amp;lt;img class="checkbox unchecked" src="unchecked.png"&amp;amp;amp;gt;
    &amp;amp;amp;lt;span class="button submit"&amp;amp;amp;gt;Save&amp;amp;amp;lt;/span&amp;amp;amp;gt;
&amp;amp;amp;lt;/div&amp;amp;amp;gt;

&amp;amp;amp;lt;script&amp;amp;amp;gt;
    $('.checkbox').on('click', app.changeMe);
    $('.submit').on('click', app.sendForm);
&amp;amp;amp;lt;/script&amp;amp;amp;gt;

Naproti tomu ARIA role mají své přesně specifikované použití a když někdo přiřadí prvku roli checkbox nebo button, je jasné, co takový prvek dělá a nelze ho zaměnit s něčím jiným.

Každý prvek může mít pouze jednu roli, ale vzhledem k tomu, že ne všechny prohlížeče a asistenční služby podporují všechny role, je možno uvést seznam rolí, přičemž platná je vždy ta první podporovaná:

&amp;amp;amp;lt;div role="menubar menu toolbar navigation"&amp;amp;amp;gt;
    &amp;amp;amp;lt;span role="menuitem button link"&amp;amp;amp;gt;
        ...
    &amp;amp;amp;lt;/span&amp;amp;amp;gt;
    ...
&amp;amp;amp;lt;/div&amp;amp;amp;gt;

Takto vytvořené menu bude menubar jen tam, kde je podporováno. Pokud ne, bude se považovat za obyčejné menu. Pokud klient neumí ani menu a menuitem, může ho považovat za toolbar s tlačítky. Pokud neumí ani toolbar, bude ho považovat za obecný navigační kontejner. A pokud neví, co dělat s tlačítky, může je nahradit za odkazy.

V CSS toho můžete využít k tomu, že můžete takto sdílet styly – např. není potřeba definovat stejný styl pro menu a navigation, ale stačí jen to obecnější pravidlo s použitím ~= porovnání (tzn. hledání slov oddělených mezerami):

[role~=navigation] { /* menu a jiné navigace */ }
[role~=link] { /* položky menu a odkazy */ }

Zbytečné ARIA role

Všechny HTML prvky mají nějakou svoji původní roli, pro kterou byly navrženy – např. odkaz načítá stránku nebo soubor, submit tlačítko odesílá formulář, atd.

Při použití takového prvku pro úkol, pro který byl navržen není potřeba roli uvádět, protože je to zbytečné – stejně jako nemusíte říkat, že kolo je kulaté a voda mokrá, není potřeba třeba uvádět, že OL je seznam:

&amp;amp;amp;lt;!-- NEPOUŽÍVAT!!! --&amp;amp;amp;gt;
&amp;amp;amp;lt;ol role=list&amp;amp;amp;gt;
    &amp;amp;amp;lt;li role=listitem&amp;amp;amp;gt;...
    &amp;amp;amp;lt;li role=listitem&amp;amp;amp;gt;...
&amp;amp;amp;lt;/ol&amp;amp;amp;gt;

Důležité je uvědomit si, že pokud v HTML5 existuje prvek, který plní vámi požadovanou funkci (seznam, článek, titulek, apod.), je vždy lepší použít daný prvek (UL, ARTICLE, LABEL, atd.) místo definování obecných DIVů a SPANů a přiřazování ARIA rolí (list, article) a vlastností (aria-labeledby).

V CSS můžete snadno používat kombinované selektory pro základní prvky a prvky s rolemi tam, kde z nějakého důvodu není vhodné HTML prvky použít:

form, [role=form] { /* formulář */ }
button, input[type=submit], [role=button] { /* tlačítka */ }
input[type=checkbox], a[role=checkbox] { /* přepínač */ }
/* atd. */

Naopak použití HTML prvku a odpovídající ARIA role pro vytvoření rozdílných prvků nebo stylů (např. HTML tlačítko bude mít kulaté rohy zatímco ARIA tlačítko bude hranaté) je vyloženě špatné a může vést jedině k problémům (co uděláte, až budete potřebovat 3D tlačítko se stínem?).

Pokud chcete naopak prvku roli sebrat, můžete ho označit jako none.

&amp;amp;amp;lt;button role=none&amp;amp;amp;gt;Takhle vypadá
    tlačítko, které nefunguje.&amp;amp;amp;lt;/button&amp;amp;amp;gt;

Odkaz

Za základní roli by se dal považovat link, což je jakýkoliv prvek, který po kliknutí (či jiné interakci) provede nějakou akci. Je jedno, jestli načte další stránku nebo jen něco změní na té současné, ale jde o to, že se nějak změní obsah stránky. Tuto roli by měli mít všechny prvky, které mají nějaký onclick (href, apod.) a nehodí se pro ně jiná role (např. button).

Například pokud checkbox „Odeslat na jinou adresu“ zpřístupní další část formuláře (pro vyplnění adresy), měl by mít roli link, aby případné pomocné nástroje správně našli, že se něco změnilo (a že samotná hodnota checkboxu je irelevantní). Z hlediska CSS pak můžete popisek checkboxu podtrhnout, aby i obyčejný uživatel používající běžný prohlížeč věděl, že se po kliknutí něco stane.

Související role je button, která se od odkazu liší tím, že by měla souviset s nějakým formulářem, toolbarem, dialogem, apod., který určuje její souvislost s okolními prvky. Tlačítka by také měla mít jednotný vzhled, aby bylo poznat, že jde o tlačítko.

Tlačítko může mít další vlastnost aria-pressed, které určuje, zda je tlačítko zmáčknuté či nikoliv a činí z něj přepínač. Tento atribut by se ale neměl používat pro animaci tlačítka při kliknutí (podobně, jako to dělá jQuery UI funkce button()).

Pokud prvek nemění viditelně obsah stránky, neměl by mít roli link, ale měl by mít roli button. Tohle ale říká ARIA specifikace; pokud je vaším primárním cílem formátování odkazů a tlačítek, tak samozřejmě záleží na tom, jak chcete daný prvek zobrazit. Nicméně již při návrhu aplikace (webové stránky) byste měli brát v úvahu rozdíl mezi odkazem (změna obsahu) a tlačítkem (změna stavu nebo odeslání dat).

Obrázek

Od prvků typu img, image, svg, canvas, apod. očekáváme, že budou zobrazovat nějakou grafiku. Pokud ale chcete zobrazit sprite nebo jiný obrázek na pozadí, měli byste prvku přiřadit roli img. Tím například umožníte čtečce správně použít atribut ALT a přečíst popis obrázku nebo ikony:

&amp;amp;amp;lt;span role=img class="icon login" alt="Login"&amp;amp;amp;gt;
&amp;amp;amp;lt;/span&amp;amp;amp;gt;

V CSS pak samozřejmě můžete ikony a sprity formátovat stejně jen na základě typu nebo role:

img.icon, .icon[role=img] { 
    display: inline-block;
    width: 1em; 
    height: 1em 
}

Podle W3C specifikace je u jakéhokoliv prvku s rolí img povinný atribut alt stejně jako u obrázků.

Roli img můžete použít i pro kontejner, který obsahuje další prvky, jejichž význam není datový či textový ale grafický; např. odstavec, který obsahuje ASCII art, by měl mít roli img.

Pokud obrázek (nebo jiný prvek) reprezentuje matematický vzorec nebo výpočet, měl by mít roli math a v atributu ALT popis vzorce. Popis může být buď text (x=⟮−b±√⟮b²−4ac⟯⟯÷2a) nebo TeX zápis (např. x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}). U textu je potřeba dát pozor na to, jak čtecí zařízení interpretuje znaky, např. a/b přečte jako „a lomítko b“ zatímco a÷b jako „a děleno b“.

Formuláře

Pro správné označení formuláře slouží skupina rolí, vycházející z původních HTML prvků. V moderních webových aplikacích je běžné, že se různé formulářové prvky, jako jsou checkboxy nebo selekty, vytváří pomocí jiných nesouvisejících prvků, třeba SPANů nebo obrázků.

Ty by pak měli mít správnou roli, aby je bylo možno správně zformátovat či použít… a také správně naformátovat v CSS.

Kromě již zmíněného tlačítka to jsou checkbox (prvek se stavy True, False nebo Mixed), combobox (jiný název pro select, tedy výběr ze seznamu), listbox (selekt v MULTI režimu), option (položka selektu), radio (volba z několika možností v radiogroup kontejneru), slider (volba z rozsahu, tedy input typu range), spinbutton (prvek se šipkami, tedy input typu number nebo podobný), switch (prvek se stavy Zapnuto a Vypnuto, např. checkbox na iPhonech) a samozřejmě základní typ textbox (tedy input bez typu nebo textarea). Souviset také může math pro matematické vzorce (např. pro výpis CAPTCHA ověření).

Všechny prvky by pak měli být v kontejneru s rolí form.

Pokud ale jde o vyhledávací formulář, měl by mít roli search a pole pro hledání roli searchbox.

Pokud má formulář nějaké speciální uspořádání prvků, měl by mít roli grid nebo treegrid (viz dále).

Pomocné ARIA atributy můžete použít k uložení stavu prvku a jeho případného správného formátování (viz další podkapitoly).

Popis prvků

Všechny formulářové prvky mohou používat atribut aria-label, který obsahuje popis prvku a je tak obdobou alt atributu u obrázků. Pokud je popis prvku již přítomen v HTML, lze místo toho využít aria-labelledby, který obsahuje ID prvku s popisem, ideálně HTML prvek label (nebo jakýkoliv jiný textový prvek). Pro další (a delší) popis prvku (např. vysvětlivky, co může obsahovat), lze použít aria-describedby, které opět obsahuje ID prvku a popisem.

  &amp;amp;amp;lt;label id=password-label for=password&amp;amp;amp;gt;
    Heslo:
  &amp;amp;amp;lt;/label&amp;amp;amp;gt;
  &amp;amp;amp;lt;input type=password id=password name=password aria-labelledby=password-label aria-describedby=password-hint /&amp;amp;amp;gt;
  &amp;amp;amp;lt;span id=password-hint&amp;amp;amp;gt;Alespoň 8 znaků,
    alespoň 1 malé písmeno, velké písmeno
    a číslo&amp;amp;amp;lt;/span&amp;amp;amp;gt;
&amp;amp;amp;lt;!-- Input má výchozí roli textbox, label a span žádnou roli nepotřebují. Odstavec P je doporučený W3C pro formátování formulářů --&amp;amp;amp;gt;

Označení editace

Pro označení způsobu editace atribut aria-required určuje, že daný prvek musí být vyplněný (a lze toho využít k CSS označení prvku). V atributu aria-describedby může být odkázán prvek s popisem, co je v prvku vyžadováno.

Atribut aria-invalid pak označuje, zda má prvek správnou (false) nebo špatnou (true) hodnotu, čehož lze opět využít, jak v CSS k formátování prvků, tak v JS k programovému odeslání formuláře. Pokud prvek atribut nemá, je z pohledu asistenčních služeb považován za validní.

Prvek, který má nevalidní hodnotu pak může atributem aria-errormessage odkazovat na prvek, který obsahuje popis chyby. Prvek s chybou by měl mít atribut aria-live=off (pokud jde o menší chybu, která nebrání uložení) nebo aria-live=assertive (pokud je to kritická chyba), čímž označí, že jeho obsah se bude měnit v závislosti na hodnotě (validitě). Prvek uvedený v aria-errormessage by neměl být vidět v případě, že je hodnota validní. Pro odkázání na popis toho, jaké hodnoty jsou validní, je potřeba použít atribut aria-describedby.

Pro vypnutí editace slouží aria-disabled a aria-readonly. Vypnuté prvky nemohou získat fokus a nelze s nimi pracovat. Prvky pouze pro čtení mohou získat fokus, ale jejich hodnota nejde změnit. Je ale třeba možné zkopírovat hodnotu readonly prvku, zatímco u vypnutého to možné není.

Pokud je editovatelný prvek momentálně ve stavu, kdy ho není možné měnit (např. čeká na validaci přes AJAX nebo ještě neobsahuje všechny potřebné DOM prvky), měl by mít atribut aria-busy=true. Tento atribut je možné použít i na celý formulář nebo jiný kontejner obsahující editovatelné prvky.

Přepínače

Pro checkbox a switch je důležitý atribut aria-checked, který obsahuje hodnotu true nebo false; pro checkbox je ještě přípustná mixed:

[role=checkbox] { 
    background-img: url(check.sprite.png)
    background-size: 1em 3em;
    width: 1em 1em;
}
[aria-checked=false] {
    background-position: 0 0;
}
[aria-checked=true] {
    background-position: 0 50%;
}
[aria-checked=mixed] {
    background-position: 0 100%;
}

Rozdíl mezi checkbox a switch s atributem aria-checked a button s atributem aria-pressed je dost sporný, protože všechny tři slouží k zapínání a vypínání nějaké funkce. To ale může hrát do karet použití s CSS, kdy každou z možností můžete použít na vytvoření jiného vzhledu bez ohledu na skutečnou funkci. Můžete tak použít vzhled stisknutého tlačítka, zaškrtnutého checkboxu a přepnutého vypínače současně v jednou vzhledu. Např. tlačítko se hodí do toolbaru, checkbox do menu (s rolí menuitemcheckbox – viz dále) nebo formuláře a přepínač jen tak do stránky.

Seznamy

U role combobox můžete použít atribut aria-autocomplete, která může mít buď hodnotu list, což znamená pouze výběr ze seznamu, nebo hodnotu inline, což znamená, že do selektu se dá ručně psát (a seznam se zobrazí teprve po zadání nějaké hodnoty). Případně hodnota both znamená, že jde jak napsat hodnotu tak ji i vybrat z připraveného seznamu. Čtvrtá hodnota none přibližně odpovídá hodnotě list s tím rozdílem, že nevyžaduje aria-owns, ale po kliku na combobox by měl kurzor přeskočit (pomocí JS) na listbox, kde je možno vybrat hodnotu.

Prvek combobox, který má typ list nebo both, by měl pak v atributu aria-owns obsahovat ID prvku, který má roli listbox a obsahuje hodnoty pro výběr (aby asistenční služby mohli nabídnout jejich výběr). Pokud je prvek s rolí listbox uvnitř prvku s rolí combobox, pak není potřeba vztah určovat v aria-owns. Aktuálně vybraná hodnota by pak měla být uložena v atributu aria-activedescendant (=vybraný potomek). Vybraný prvek (option) lze naopak označit atributem aria-selected=true.

[role=combobox][aria-owns=countries] {
    /* formátování seznamu vlajek */
}
[role=combobox][aria-activedescendant=cs] {
    background-image: czech.png;
}
[role=option][aria-selected=true] {
    background-color: yellow;
}
[role=combobox][aria-autocomplete=inline],
[role=combobox][aria-autocomplete=both] {
    /* formátování textového pole */
}

Dále je možno combobox rozšířit o atributy aria-expanded, který určuje, zda má sbalený (false) nebo rozbalený (true) seznam, a atribut aria-haspopup, která by měla být nastavena na true, pokud jde rozbalit, nebo false, pokud žádné vhodné možnosti nejsou k dispozici.

Související prvek s rolí listbox se nedá rozbalit, ale obsahuje přímo viditelné prvky s rolí option. Ty mohou obsahovat buď text (nebo jiné textové prvky), nebo prvky s rolí img a atributem alt (pro výběr z obrázků). Role option se nesmí použít jinde než uvnitř listbox kontejneru! HTML prvek select se považuje za prvek, který má současně role combobox i listbox a může tak obsahovat ARIA atributy obou těchto rolí a může obsahovat prvky s rolí option.

Další atribut aria-orientation může obsahovat buď vertical nebo horizontal hodnotu, která určuje, kterým směrem jsou prvky v seznamu seřazeny – a vy ji můžete použít třeba pro definování flexbox vlastností v CSS, aby se položky správně uspořádaly.

Trochu jiný druh seznamu je role list (viz dále) a její položky listitem. Tyto odpovídají HTML prvkům OL a UL (a LI pro listitem), které se od listboxu liší tím, že v nich nelze nic vybírat a jen zobrazují nějaké položky. List může obsahovat jen listitem nebo group položky a obráceně listitem může být pouze uvnitř list nebo group kontejnerů.

Výběr hodnoty

Prvky slider a spinbutton mají společné vlastnosti aria-valuemin, aria-valuemax a aria-valuenow, které určují minimální, maximální a aktuální hodnotu. Tyto atributy můžete v Javaskriptu použít pro ovládání prvku a nepotřebujete tak používat obdobné data-* atributy nebo jiné proměnné.

setSlider = function(value) {
    el = $('#slider');
    if (el.attr('aria-valuemin') &amp;amp;amp;lt;= value &amp;amp;amp;amp;&amp;amp;amp;amp; el.attr('aria-valuemax') &amp;amp;amp;gt;= value) {
        el.attr('aria-valuenow', value);
    }
}

V CSS pak můžete tyto hodnoty použít např. pro sprity, které budou vytvářet vzhled slideru:

[role=slider] { 
    background-image: url(slider.png);
}
[role=slider][aria-valuenow=1] {
    background-position: 0 -1em;
}
/* atd. */

Atribut aria-valuetext může obsahovat hodnotu včetně jednotek (např. aria-valuetext="100%"). Čtecí zařízení by pak mělo upřednostnit přečtení textové hodnoty místo numerické (aria-valuenow).

Pokud prvek neumožňuje hodnotu vybrat, ale jen ji zobrazuje, přísluší mu role progressbar. Trochu (ne)související je scrollbar. Prvky s jednou z těchto rolí mohou také využívat stejné atributy pro určení rozsahu a hodnoty.

Textový vstup

Prvky s rolí textbox mohou mít atribut aria-multiline, který určuje, zda zabírají jen jeden řádek (input) nebo více (textarea), přičemž by nemělo jít o to, jak vypadají graficky, ale zda stisk Enteru vloží nový řádek nebo ne (a třeba odešle formulář). Nicméně pro použití v CSS se můžete zaměřit na jejich grafický rozdíl místo funkčního.

Pole pro hledání nebo filtrování by mělo mít roli searchbox místo textbox.

Příslušnost do kontejneru

Pro všechny případy, kdy je uvedeno musí být v kontejneru s určitou rolí, lze taktéž využít atribut aria-owns u kontejneru, kde uvede mezerami oddělený seznam ID prvků, které do něj patří. Ty se pak nemusí fyzicky nacházet uvnitř kontejneru, ale mohou být kdekoliv jinde na stránce a stále splní pravidla přístupnosti.

&amp;amp;amp;lt;div role=list aria-owns="item1 item2 item3"&amp;amp;amp;gt;
    &amp;amp;amp;lt;!-- prázdný --&amp;amp;amp;gt;
&amp;amp;amp;lt;/div&amp;amp;amp;gt;

&amp;amp;amp;lt;!-- mezitím v jiné části HTML --&amp;amp;amp;gt;
&amp;amp;amp;lt;span role=listitem id=item1&amp;amp;amp;gt;položka 1&amp;amp;amp;lt;/span&amp;amp;amp;gt;
&amp;amp;amp;lt;span role=listitem id=item2&amp;amp;amp;gt;položka 2&amp;amp;amp;lt;/span&amp;amp;amp;gt;
&amp;amp;amp;lt;span role=listitem id=item3&amp;amp;amp;gt;položka 3&amp;amp;amp;lt;/span&amp;amp;amp;gt;

V CSS se tohle ale příliš nehodí, protože nemůžete formátovat prvek podle toho, zda přísluší určitému kontejneru, když v něm není umístěn.

Seznamy, stromy, tabulky a gridy

Pro uspořádání prvků na stránce slouží seznamy (list), tabulky (table), stromy (tree) a gridy (grid nebo treegrid).

Pro jednorozměrné zobrazení slouží seznam nebo strom. Pro dvourozměrné zobrazení (sloupce a řádky) slouží tabulky a gridy. Seznam a tabulka slouží pro statické zobrazení dat bez možnosti interakce (vyjma skrolování) zatímco grid slouží pro zobrazení dvourozměrných dat, která lze editovat nebo jinak s nimi manipulovat.

Strom, jak v jednorozměrné tak i dvourozměrné podobě, umožňuje jednotlivé položky (řádky či sloupce) skrývat nebo zmenšovat (collapse/expand).

Seznam

Seznam může obsahovat pouze prvky s rolí listitem nebo group. Role list odpovídá HTML prvkům UL a OL, listitem odpovídá LI.

Pokud lze prvek v seznamu vybrat (ať už uživatelsky nebo programově), lze ho označit atributem aria-current. Hodnota může být buď true, což prostě označuje vybranou položku, nebo může mít jednu z hodnot page, step nebo location, které lze použít, pokud daný seznam označuje stránky nebo jiné prvky rozdělení, mezi kterými se může uživatel pohybovat.

Pokud seznam (nebo tabulka či grid) reprezentuje kalendář nebo čas, může mít jeho atribut aria-current hodnotu date nebo time, což pak označuje aktuální den nebo čas. Pokud lze v kalendáři vybrat jiný den než dnešek (pak by kalendář měl mít roli grid), měl by být vybraný den (reprezentovaný prvkem gridcell) označen atributem aria-selected=true.

Seznam obsahující nějaké prvky definované skupiny (např. uživatele, zaměstnance, seznam zboží, atd.) můžete označit rolí directory.

Tabulka

Tabulka odpovídá HTML prvku TABLE a může obsahovat jen prvky s rolí row (odpovídá TR) nebo rowgroup (THEAD, TBODY a TFOOT), který opět může obsahovat pouze prvky s rolí row.

Řádek row se pak skládá z buněk reprezentovaných prvky s rolí cell, což odpovídá HTML prvku TD. Speciální role columnheader a rowheader jsou určeny pro buňky, které obsahují popisek daného sloupce nebo řádky stejně jako HTML prvek TH (HTML obdoba rowheader je <th scope=row>).

Tabulka může mít atributy aria-colcount a aria-rowcount, které určují, kolik řádek a sloupců daná tabulka má. Tyto atributy jsou určeny pro případ, kdy všechny řádky nebo sloupce nejsou přítomny v DOMu a budou se dynamicky načítat např. při skrolování nebo přepínání stránek. Pokud je celá tabulka přítomna v DOMu, není potřeba (z pohledu ARIA specifikace) tyto hodnoty uvádět. Nicméně pro zpracování CSS nebo JS můžete tyto hodnoty využít:

$table.attr('aria-rowcount',
      $table.find('tr').length);

Pokud není počet řádků znám, měla by hodnota být -1. Jednotlivé řádky a sloupce můžete číslovat pomocí atributů aria-rowindex a aria-colindex.

&amp;amp;amp;lt;div role=table aria-rowcount=2 aria-colcount=3&amp;amp;amp;gt;
  &amp;amp;amp;lt;div role=row aria-rowindex=1&amp;amp;amp;gt;
    &amp;amp;amp;lt;div role=columnheader aria-colindex=1&amp;amp;amp;gt;A&amp;amp;amp;lt;/div&amp;amp;amp;gt;
    &amp;amp;amp;lt;div role=columnheader aria-colindex=2&amp;amp;amp;gt;B&amp;amp;amp;lt;/div&amp;amp;amp;gt;
    &amp;amp;amp;lt;div role=columnheader aria-colindex=3&amp;amp;amp;gt;C&amp;amp;amp;lt;/div&amp;amp;amp;gt;
  &amp;amp;amp;lt;/div&amp;amp;amp;gt;
  &amp;amp;amp;lt;div role=row aria-rowindex=2&amp;amp;amp;gt;
    &amp;amp;amp;lt;div role=cell aria-colindex=1&amp;amp;amp;gt;a&amp;amp;amp;lt;/div&amp;amp;amp;gt;
    &amp;amp;amp;lt;div role=cell aria-colindex=2&amp;amp;amp;gt;b&amp;amp;amp;lt;/div&amp;amp;amp;gt;
    &amp;amp;amp;lt;div role=cell aria-colindex=3&amp;amp;amp;gt;c&amp;amp;amp;lt;/div&amp;amp;amp;gt;
  &amp;amp;amp;lt;/div&amp;amp;amp;gt;
&amp;amp;amp;lt;/div&amp;amp;amp;gt;

Pokud prvek zabírá více než jednu buňku, měla by mít atribut aria-colspan nebo aria-rowspan, což odpovídá HTML atributům rowspan a colspan u TD.

Pokud je tabulka seřazena podle určitého sloupce nebo řádky, můžete buňku s rolí columnheader nebo rowheader označit atributem aria-sort s hodnotou ascending (vzestupně), descending (sestupně), other (jiný způsob řazení) nebo none (není řazeno podle tohoto sloupce či řádky, ale je možno je seřadit). Stejný atribut platí i pro grid a treegrid, pokud jdou řadit.

Strom

Pro seznam nebo tabulky, kde lze prvky schovávat je určen strom (role tree nebo treegrid).

Jednorozměrný strom se chová stejně jako seznam s tím rozdílem, že místo listitem obsahuje prvky s rolí treeitem nebo group, která pak obsahuje treeitem. Dvourozměrný strom se pak chová stejně jako tabulka a může se skládat z prvků s rolemi row, rowgroup, cell, columnheader a rowheader se stejnými pravidly jako tabulka. Navíc může obsahovat prvky s rolí gridcell, pokud se chová stejně jako grid (viz dále). Pak může používat i další atributy gridu.

Pro označení stavu slouží atribut aria-expanded, který určuje, zda je prvek vidět celý (true) nebo jen částečně (false). Pokud je prvek zcela skryt, měl by mít atribut aria-hidden s hodnotou true:

[aria-expanded=true] { height: auto; }
[aria-expanded=false] { height: 1em; }
[aria-expanded][aria-hidden=true] { 
    display: none; 
}

Pokud je ve stromu prvek, který neskrývá nebo nerozšiřuje sám sebe, ale jiný prvek – např. tlačítko, které zobrazí následující DIV, je potřeba, aby prvek (tlačítko) měl atribut aria-expanded a současně atribut aria-controls, který pak obsahuje mezerou oddělený seznam IDček prvků, které se zobrazí, pokud po nastavení vlastnosti aria-expanded=true. Tuto vlastnosti lze v CSS použít pouze pokud jsou prvky za sebou díky operátoru +. Pokud nejsou, je potřeba je použít v JS a zobrazení ovládač programově.

...
&amp;amp;amp;lt;div role=treeitem aria-expanded=false aria-controls=expand-me onclick="show(this)"&amp;amp;amp;gt;Rozbalit/Sbalit&amp;amp;amp;lt;/div&amp;amp;amp;gt;

&amp;amp;amp;lt;div id=expand-me role=treeitem aria-hidden=true&amp;amp;amp;gt;
    Zde jsou uvedeny detaily položky&amp;amp;amp;lt;/div&amp;amp;amp;gt;

&amp;amp;amp;lt;script&amp;amp;amp;gt;
function show(el) {
    var expanded = $(el).attr('aria-expanded');
    el.attr('aria-expanded', !expanded);
    el.next().attr('aria-hidden', !expanded);
}
&amp;amp;amp;lt;/script&amp;amp;amp;gt;

Grid

Poslední ze skupiny je grid a jeho mutace treegrid. Grid slouží pro zobrazení dvourozměrné tabulky, která obsahuje nějaké inputy, tlačítka či jiné interaktivní prvky s příslušnými rolemi (link, switch, apod.).

Dá se říci, že ARIA grid je předobrazem připravovaného CSS3 gridu, který má nahradit tabulkový layout pro rozložení stránky. Na druhou stranu role grid nebo treegrid neříká nic o vizuálním vzhledu prvků, takže není přímo nutné, aby vypadali jako tabulka nebo strom.

Grid můžete použít třeba v případě, že chcete uspořádat sadu checkboxů nebo radioboxů do sloupců a řádek pro úsporu místa, i když třeba v resposivním (mobilním) layoutu nebudou zobrazeny jako tabulka, ale jako seznam.

Grid má stejná pravidla jako tabulky nebo strom (podle toho, jak funguje) s tím rozdílem, že koncový prvek (buňka) musí mít roli gridcell (místo cell). Místo gridcell lze použít columnheader nebo rowheader, kde již není potřeba určovat, že jde speciální o gridové buňky. Ostatní role a jejich vztah zůstává stejný jako v tabulce, tedy role row, rowgroup, atd. a atributy aria-rowcount, aria-rowindex, atd. Editovatelné prvky (a jejich rodiče) pak mohou mít atributy formuláře, např. aria-required nebo aria-disabled. Hodnota atributu se pak přenáší z kontejnerů (grid, row, atd.) na děti (gridcell, textbox, atd.).

Formulářové atributy mají vliv pouze na prvky s rolí, která umožňuje editaci (button, textbox, checkbox, atd.). Pro prvky s rolí bez možnosti editace (link, img, atd.) není potřeba atributy uvádět a také nemá jejich hodnota vliv na dané prvky (takže třeba disabled link pořád reaguje na kliknutí).

Rozložení stránky

ARIA role lze použít i pro prvky stránky, jako je hlavička, tělo, menu, atd.

Části stránky

Hlavičku stránky můžete označit rolí banner, což je oblast, která by měla být společná pro všechny podstránky (např. logo, jméno serveru nebo firmy, případně jednoduché menu). Každá stránka by měla mít jen jeden banner. Zhruba odpovídá HTML5 tagu HEADER, ale těch může být ve stránce více.

Hlavní obsah stránky (tělo) označuje role main, která by měla být použita pro prvek, který obsahuje vše podstatné pro danou stránku a naopak neobsahuje společné části (hlavičku stránky, menu, atd.). Každá stránka by měla mít jen jeden hlavní prvek. V HTML5 by to měl být prvek MAIN, který již tuto roli nepotřebuje specifikovat.

Ostatní ne-hlavní části stránky, které nelze označit jinou rolí, by měli mít roli complementary. Na zpravodajském serveru takto můžete označit oblast s předpovědí počasí, stavem burzy nebo plánovanými (sportovními či politickými) akcemi, atd. Odpovídá HTML5 prvku ASIDE.

Menu

Role menu je speciální typ seznamu (list), který obsahuje navigační položky označené rolí menuitem. Pro menší menu pouze s několika položkami lze použít roli menubar. Směr orientace menu označuje atribut aria-orientation, který je ve výchozím stavu vertikální pro menu a horizontální pro menubar. Pro přepínatelné položky menu lze použít role menuitemcheckbox nebo menuitemradio, které mohou být vnořeny do prvku s rolí group. Ty se chovají stejně jako formulářový checkbox a radio.

Pro jiné navigační prvky, které nesplňují pravidla menu (z vašeho pohledu), lze použít roli navigation (odpovídá HTML5 prvku NAV), která může obsahovat libovolné prvky, obvykle s rolí link. Prvek, který se podobá menu, ale neobsahuje odkazy může být toolbar. Navigace i toolbar mohou mít atribut aria-orientation. Toolbar je ve výchozím stavu horizontální.

Typ obsahu

Prvek, který obsahuje čitelný text, můžete označit rolí document. Naopak prvek, který obsahuje nějaké netextová data, můžete označit rolí application. Dokument a aplikace může obsahovat vnořený prvek main, který označí hlavní obsah. Pokud je dokument vložen uvnitř aplikace, asistenční služby (např. text-to-speech) by měli ignorovat vše uvnitř aplikace kromě prvků uvnitř dokumentu:

&amp;amp;amp;lt;div role=application class=reklama&amp;amp;amp;gt;
  &amp;amp;amp;lt;div id="data"&amp;amp;amp;gt;data pro skript&amp;amp;amp;lt;/div&amp;amp;amp;gt;
  &amp;amp;amp;lt;div role=document&amp;amp;amp;gt;
    &amp;amp;amp;lt;h2&amp;amp;amp;gt;Reklama:&amp;amp;amp;lt;/h2&amp;amp;amp;gt;
    &amp;amp;amp;lt;span role=main&amp;amp;amp;gt;
            Kupte si naši...
    &amp;amp;amp;lt;/span&amp;amp;amp;gt;
  &amp;amp;amp;lt;/div&amp;amp;amp;gt;
  &amp;amp;amp;lt;script&amp;amp;amp;gt;/* animace reklamy */&amp;amp;amp;lt;/script&amp;amp;amp;gt;
&amp;amp;amp;lt;/div&amp;amp;amp;gt;

Poznámka: role Aplikace neodpovídá pojmu webová aplikace (jako celek) ale spíše označuje nějakou funkční část stránky nebo webové aplikace, která se skládá z viditelných (dokumenty) a neviditelných (skripty, styly, šablony, apod.) částí. Může jít např. o strom a s ním související skripty a styly, které ovládají jeho rozbalování. Jako Aplikaci lze označit i část, která vyžaduje interakci, ale nedá se označit jako formulář – např. hra vykreslovaná do canvasu.

Pokud prvek neobsahuje čitelná data, ale zároveň není interaktivní, aby šel označit jako aplikace, můžete použít roli presentation. Jediným úkolem prezentačního prvku je umožnit mu přiřadit CSS. Také může jít o obrázky, které nemají atribut alt.

Prvky, které na stránce vytváří vizuální oddělovače, které normální uživatel vidí, ale asistenční služby nebo roboti (např. GoogleBot) je ignorují, mají roli separator (HTML prvek HR). Pokud je úkolem prvku graficky nahrazovat scrollbar, může mít k tomu přímo určenou roli scrollbar (ten se chová stejně jako vertikální progressbar a má stejné atributy – viz formuláře výše).

Prvky s rolemi aplikace, prezentace, scrollbar nebo none by měly být neviditelná pro asistenční služby (např. text-to-speech).

Obsah

Pokud prvek představuje kontejner pro další textové prvky, které dohromady nějak souvisejí, a nechcete ho udělat jako HTML5 ARTICLE, můžete ho označit rolí article. Daný prvek nemusí být přímo článek, ale může se jednat o cokoliv jiného (např. nápověda, vtip dne, uživatelské komentáře, atd.). Pokud jde o prvek, do kterého dynamicky přibývají (nebo naopak ubývají) zprávy nahoru nebo dolu, měl by být naopak označen rolí log (např. online zpravodajství, komentáře bez vnořování, atd.). Pokud prvek obsahuje nedůležité nebo často se měnící informace, můžete použít roli marquee (např. aktuální zprávy ze světa, jména online uživatelů, atd.)

Kontejner, který obsahuje prvky s rolí article můžete označit rolí feed. Jednotlivé články pak můžete seřadit pomocí atributu aria-posinset a pokud nejsou načteny všechny, uvést jejich počet do aria-setsize.

Hlavičku dokumentu, aplikace, článku nebo feedu můžete označit rolí heading (což odpovádá HTML prvkům H1, H2, atd.), který by měla být přes atribut aria-labeledby propojena s daným kontejnerem. Hlavička zároveň může fungovat jako rozbalovátko daného kontejneru, pokud má atribut aria-expanded a aria-controls (více viz informace o stromech).

Část stránky nebo dokumentu, která s ní souvisí, ale není důležitá, označuje role note. Související část obsahující systémové nebo právní informace (copyright, jméno autora, apod.) má roli contentinfo (každý dokument, aplikace nebo článek by měli mít vždy jen jeden contentinfo prvek – propojení je přes aria-owns).

Měnící se obsah

Pokud prvek obsahuje nějakou nedůležitou, ale v čase se měnící informaci, může mít roli status. Pokud jde naopak o důležitou informaci, je pro ni rezervována role alert. Pro prvky, které zobrazují aktuální čas nebo nějaký odpočet, je určena role timer.

Ostatní obsah

Oblast stránky, která není hlavní ale zároveň obsahuje nesourodé potomky (aby šel označit jako menu, článek, apod.), může mít roli region. Tuto roli by měli mít všechny DIVy ve stránce, které obsahují další důležité prvky a nemají žádnou konkrétnější roli. V HTML5 byste místo takových DIVů měli používat tag SECTION.

Pro nahrazení HTML prvků DL-DT-DD můžete použít role termdefinition, které označují výraz a jeho popis. Role definition může nahradit i HTML5 prvek DFN (definice, jejíž výraz je určen v atributu title). Definice by měla mít atribut aria-labelledby odkazující na term nebo aria-label (obdoba DFN.title) s výrazem, který definuje. Pokud je výraz (term) současně odkazem (a definice se zobrazí až po kliknutí), musí mít roli link (pro použití v CSS může mít roli "link term" a pravidla pak definovat [role~=term]), aby bylo možno na něj správně „kliknout“ pomocí asistenčních služeb. Definice se pak přes aria-labelledby odkáže na tento link (prože labelem může být cokoliv, co má ID).

Pokud prvek (obvykle DIV) obsahuje čistý text a z nějakého důvodu to není P, SPAN, apod., měl by mít roli text. Tato role je také určena pro prvky, které nemohou mít žádnou jinou vhodnější roli a přesto jsou obsahově důležité.

Použít se dá i v případě, že prvek obsahuje text, který ale není čitelný běžným způsobem a vyžaduje popis – asistenční služby pak přečtou tento popis:

&amp;amp;amp;lt;span role=text aria-label="Hodnocení: 3 z 5 hvězdiček"&amp;amp;amp;gt;
        ★★★☆☆︎
&amp;amp;amp;lt;/span&amp;amp;amp;gt;
&amp;amp;amp;lt;!-- čtecí zařízení přečte popis --&amp;amp;amp;gt;

&amp;amp;amp;lt;span role="img text" alt="srdce" aria-label="srdce"&amp;amp;amp;gt;
        ♥︎
&amp;amp;amp;lt;/span&amp;amp;amp;gt;
&amp;amp;amp;lt;!-- pokud čtecí zařízení neumí číst ALT u obrázků přečte alespoň popis textu --&amp;amp;amp;gt;

Prvek, který neobsahuje text, ale reprezentuje jeden prvek stránky může mít role widget (obecný grafický prvek, např. obrázek), command (prvek provádějící nějakou akci, např. odkaz) či composite (prvek skládající se z několika podprvků, např. tabulka). Tyto role jsou v ARIA definici označeny jako abstraktní a neměli by se používat, ale slovo „neměly“ („should not„) znamená, že pokud se vám hodí pro CSS nebo JS řízení, můžete je použít. Jen nepočítejte s tím, že tím získají nějaké vlastnosti, a vždy si dobře rozmyslete, jestli není lepší použít role img, link, table, apod.).

Prvky s nespecifickými rolemi jako region, group, widget, apod. mohou mít atribut aria-roledescription s bližším popisem toho, co prvek představuje. Popis by měl být určený pro lidi (human-readable) a měl by být v jazyce dané stránky, např. „reklama na boty“ místo „google-ad-shoes“. Čtecí zařízení pak obvykle tento popisek kombinuje s aria-label pro přesnější označení toho, co uživatel „vidí“ (i když je slepý, takže neví, co „vidí“). Pokud vás až tak nezajímá přístupnost stránek, nebo nemáte více jazykových mutací stránky, můžete tento atribut použít k bližší specifikaci prvků, jejichž role není pro použití v CSS dostatečně specifická.

[role=list][aria-roledescription=gallery] { /* seznam obrázků */ }
[role=link][aria-roledescription=attachment] { /* odkaz pro stažení souboru */ }

Dialogy

Pro popup části stránky jsou určeny role dialog, alertdialog a tooltip. Rozdíl je následující: dialog je popup, který se zobrazuje očekávaně po kliknutí na související tlačítko nebo odkaz. Alert dialog je naopak popup, který se objeví neočekávaně (ať už po kliku nebo zcela samostatně) a zpravidla obsahuje nějaké upozornění, chybu nebo dotaz. Tooltip je pak malý dialog, zpravidla zcela bez tlačítek, které se zobrazí po najetí nebo kliknutí na nějakou část stránky (ne nutně tlačítko nebo odkaz).

HTML5 prvek DIALOG má automaticky roli dialog a lze ho změnou role použít na alertdialog.

Alert může obsahovat tlačítka nebo další prvky pro vstup uživatele a odpovídá javaskriptovým funkcím alert(), confirm() a prompt(). Dialog by měl obsahovat nějaké interakční prvky (minimálně tlačítko OK nebo křížek pro zavření).

Dialog a Alert by měly mít nějaký titulek označený atributem aria-labelledby. Pokud ho nemají, měli by mít alespoň aria-label se jménem dialogu.

Prvek, který po kliknutí nebo najetí otevírá nějaký dialog nebo tooltip by měl mít atribut aria-haspopup s hodnotou true a přes aria-owns odkazovat na daný dialog. Tím umožní asistenčním službám (nebo javaskriptu) automaticky daný dialog najít a zobrazit (např. přečíst jeho titulek z aria-labelledby).

Taby

Pro zobrazení většího množství obsahu na malém místě můžete použít role pro Taby. Je přitom jedno, jestli je graficky provedete jako taby, harmoniku (accordion), kolotoč (carousel) nebo jinak (vyjma rozbalovacího stromu, ten má vlastní roli).

Hlavní prvek se označí rolí tablist a do něj se vloží prvky s rolemi tab a tabpanel. Prvky tab musí být uvnitř tablistu nebo být vypsány v atributu aria-owns. Prvky tabpanel nemusí být uvnitř tablistu, ale měly by mít atribut aria-labelledby, který odkazuje na příslušný tab a obráceně tab by měl atributem aria-controls odkazovat na svůj tabpanel.

Seznam tabů (záložek) se řídí atributy aria-posinset, který určuje pořadí tabu a aria-setsize určující počet tabů, pokud nejsou všechny přítomny v DOMu (ano, velikost je potřeba určit pro každý tab, nikoliv pro tablist). Pokud není počet znám, měla by být hodnota -1.

Aktuálně vybraný tab se pak označí atributem aria-selected=true.

Aktualizace stránky

Pokud se nějaká část stránky mění, měla by mít atribut aria-live, který může obsahovat hodnoty polite (změna není důležitá a není podstatné, zda ji uživatel zaregistruje), assertive (změna je důležitá a uživatel o ní musí vědět) nebo off (obsah se může měnit, ale změna není podstatná nebo je očekávaná).

Prvky s rolí status mají stav polite, role alert odpovídá assertive a timer má hodnotu off (protože u timeru čekáte, že se bude měnit). Prvky s rolemi log a marquee by měli také mít tento atribut, ale úroveň důležitosti záleží čistě na konkrétní situaci. Např. u online zpravodajství o hokejovém zápase (pomocí log článku) může být hlášení o tom, kteří hráči jsou zrovna na ledě s prioritou off (protože hráči se mění pořád a není to podstatné), informace o faulu nebo vyloučení může mít prioritu polite a gól má pak samozřejmě prioritu assertive.

Související atribut je aria-atomic, která označuje část, která jako celek souvisí se změnou obsahu. Pokud má prvek atribut aria-live a prohlížeč zaregistruje jeho změnu, projde všechny jeho rodiče a hledá roli aria-atomic. Pokud najde u některého rodiče hodnotu aria-atomic=true, zpracuje změnu jako by se změnil celý rodič. Pokud naopak najde rodiče, který má nastaveno aria-atomic=false, znamená to, že změna se týká jen toho prvku, který se skutečně změnil. Stejně to můžete použít v Javaskriptu pro nalezení rodiče, jež je potřeba změnit při změně prvku:

el.on('myEvent', function() {
    var parent = $(this)
        .closest('[aria-atomic]');

    if (parent.attr('aria-atomic')) {
        //označ kontejner jako změněný
    }
    else {
        //označ pouze THIS jako změněný
    }
});

Prvek, u něhož právě probíhá aktualizace (např. odeslal AJAX a čeká na odpověď), můžete označit atributem aria-busy=true. Naopak prvek, který momentálně žádnou změnu neplánuje může mít aria-busy=false.

Dále můžete prvek, který čeká na změnu nebo se právě změnil, označit atributem aria-relevant, který může svojí hodnotou určit, jaká změna proběhla (nebo pravděpodobně proběhne). Atribut má 3 základní hodnoty: additions znamená, že do prvku přibudou nové elementy, removals naopak znamená odebrání prvků a text indikuje změnu textu (nebo i jiného netextového obsahu) stávajících prvků.

Hodnoty je možno kombinovat a vytvořit tak např. „additions text“ (přibudou nové prvky a stávající se změní), „additions removals“ (přibudou i ubudou prvky) nebo „removals text“ (ubudou prvky a ostatní se změní). Pokud dojde ke všem třem akcím, můžete použít buď „additions removals text“ nebo souhrnné „all„.

Atribut by ale měl označovat vždy jen tu nejdůležitější změnu a nemůže tak sloužit např. jako návod pro skript co všechno je potřeba při změně udělat. Pokud např. dojde k vymazání prvků v log nebo marguee jen proto, že nové prvky vytlačí ty nejstarší, akci removals není nutno (není žádoucí) uvádět v atributu. Stejně tak pokud se třeba změní indexy řádek v logu kvůli novým prvkům, není potřeba uvádět text, protože vlastní hodnoty se nezměnily. Akce by se měla týkat jen základních prvků, takže třeba doplnění EM a STRONG do nového textu není potřeba označovat jako additions, ale postačí jen text (neboť tyto prvky jsou zde chápány jako součást změněného textu). Naopak pokud programově jen změníte obsah stávajících DIVů, ale z pohledu uživatele budou reprezentovat nové prvky, měla by akce být additions nebo „additions removals“ místo pouhého text.

Drag & Drop

Funkce česky zvaná Chyť a pusť (více známá jako přetažení) má též podporu v ARIA atributech, ale plánuje se její změna, takže uvedené berte s rezervou.

Prvek, který je právě tažen (drag) lze označit atributem aria-grabbed.

Hodnota true znamená, že prvek je právě tažen (např. myší nebo prstem) nebo alternativně může označovat prvek, který sice zrovna není tažen, ale je k tomu připraven (např. u lidí, zařízení, či asistenčních služeb, kteří/které nejsou schopny Drag&Drop provést najednou – tedy držet prvek a zároveň pohybovat kurzorem; též známé jako ClickLock).

Naopak hodnota false znamená, že prvek není tažen ani k tomu není připraven, ale tažení podporuje a je možno ho přetáhnout. Prvky, které přetažení vůbec nepodporují, nesmějí tento atribut mít, nebo musejí obsahovat hodnotu undefined.

Druhý související atribut je aria-dropeffect, který určuje, že prvek je právě tažen (a tím je myšleno skutečně tažen – na rozdíl od předchozího atributu, který může označovat pouhou připravenost) a zároveň říká, co se s daným prvkem stane, pokud ho upustíte (drop).

Povolené hodnoty jsou copy (vytvoří se kopie prvku), move (původní prvek se přesune), link (vytvoří se odkaz nebo reference na původní prvek) nebo popup (konkrétní akci bude možno vybrat až po upuštění prvku, např. z popup menu). Hodnota execute označuje, že prvek je možno upustit, ale dojde k nějaké jiné akci s prvkem (např. se vymaže nebo vytiskne).

Poslední hodnota je none a označuje, že v daném místě není možno prvek upustit (drop) a v případě upuštění k ničemu nedojte. Z toho je vidět, že hodnota atributu aria-dropeffect se může (resp. měla) měnit v průběhu tažení a lze tak podle ní měnit vzhled taženého prvku nebo kurzoru. Naopak není možno atribut použít pro označení způsobu, co se stane teprve až uživatel prvek přetáhne, protože prvek, který zrovna není tažen, musí mít hodnotu none nebo atribut vůbec nemít.

ARIA a jQuery

jQuery (zatím) aria atributy přímo nepodporuje, ale může s nimi pracovat stejně jako s jakýmikoliv jinými HTML atributy, což je ukázáno v příkladech výše.

Pokud plánujete používat ARIA, můžete si práci usnadnit pluginem jquery.aria (nebo na GitHubu jquery-aria), který přidává funkce pro práci s aria atributy (stejně jako teď pracujete s data-* atributy) a s rolemi (stejně jako se pracuje se třídami).

Případně můžete využít mojí úpravu s dalšími funkcemi.

1 komentář u „ARIA jako CSS nástroj“

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *