Szaktanácsadás akadálymentes honlap készítéséhez

Örökbefogadás az aria-owns attribútummal

Szülő-gyerek kapcsolat

A szülő-gyerek kapcsolat egy nagyon fontos koncepció a HTML, a DOM és az ARIA specifikációban is. Amikor egy HTML jelölőelembe elhelyezünk valamilyen tartalmat, akkor ez a tartalom alkotja majd az adott elem gyermekeit a DOM fában, és az abból leképzett akadálymentességi fában is.

Vegyük például a következő HTML kódot:

<ul>
    <li>ALma</li>
    <li>Körte</li>
    <li>Szilva</li>
</ul>

Ennek alapján egy olyan reláció jön létre a DOM fában, ahol az ul elemnek három li gyermekeleme van.

  • ul
    • li
    • li
    • li

Ezt a DOM struktúrát használja fel a böngészőprogram az ARIA szabványban specifikált akadálymentességi fa elkészítéséhez. Minden olyan DOM objektumból létrehoz egy akadálymentességi objektumot, ami a kisegítő technológiák (például a képernyőolvasó programok) számára érdekes lehet.

Esetünkben egy list szereppel rendelkező akadálymentességi objektum, és annak három listitem szereppel rendelkező gyermeke kerül az akadálymentességi fába.

  • list
    • listitem
    • listitem
    • listitem

Az ARIA szabvány alapján a DOM elem akadálymentességi gyermekeinek hívjuk az adott elem akadálymentességi objektumának összes gyermekét az akadálymentességi fában.

Fontos, hogy az akadálymentességi gyermekek köre nem minden esetben egyezik meg a HTML kódban, illetve a DOM fában lévő gyermekekkel. Lássunk erre egy példát:

<article>
    <h1>Ez itt egy címsor</h1>
    <div>
        <p>Ez itt egy bekezdés</p>
    </div>
    <h2 hidden>Ez egy másik címsor</h2>
</article>

A fenti kódban az <article> jelölőelembe közvetlenül három másik jelölőelem van beágyazva. Egy <h1>, egy <div>, és egy <h2>. Fontos lesz, hogy a <h2> elemnek egy hidden attribútuma van.

Az említett beágyazás a DOM fában is visszaköszön, hiszen az article elemnek egy h1, egy div, és egy h2 gyermeke van. A p elem már unokának számít, hiszen a div gyermek gyermeke.

  • article
    • h1
    • div
      • p
    • h2

Ha megnézzük, hogy a fenti DOM fából milyen akadálymentességi fa generálódik, akkor azt fogjuk látni, hogy az article szereppel rendelkező akadálymentességi objektumnak három helyett csak két gyermeke lesz: egy heading szerepű objektum, ami a h1-ből készült, és egy paragraph szerepű, ami unokából gyermekké „lépett elő”.

  • article
    • heading
    • paragraph

De vajon hova lett a div és a h2?

Az ARIA szabvány 1.3-as verziója alapján (ami jelen cikk írásakor még nem egy véglegesített verzió) a böngészőprogramok az akadálymentességi fa generálásakor a generic szereppel rendelkező elemeket (mint például a div) figyelmen kívül hagyhatják, amennyiben az adott elemhez nem tartozik az ARIA szabványban megengedett attribútum. Ennek oka, hogy az ilyen elemek abszolút lényegtelenek az akadálymentesség szempontjából. Ettől persze még a gyermekeik bekerülhetnek az akadálymentességi fába, ahogy a példánkban a p elem is.

Azok az elemek is kihagyhatók, amelyek a hidden attribútummal, vagy a display:none, illetve a visibility:hidden CSS szabállyal vannak elrejtve. Példánkban ilyen a h2 elem. Fontos, hogy a rejtett elemek leszármazottai is rejtve maradnak.

A testvéri viszony

Akadálymentességi szempontból sokszor közvetlenül nem is az elemek közötti szülő-gyerek kapcsolat a fontos, hanem inkább az ennek nyomán létrejövő testvér kapcsolat. Ennek oka, hogy sok kisegítő technológia, így például a képernyőolvasó programok használata is jellemzően egy lineáris bejáráson alapul. Ilyenkor a felhasználó egy adott elemről sokszor a vele szomszédos következő vagy előző elemre, vagyis az elem valamelyik közvetlen testvérére lép át. Az elemek sorrendje tehát döntően befolyásolhatja az értelmes olvasási sorrendet, illetve interaktív elemek esetén a működtethetőséget is.

Utóbbira egy klasszikus és gyakori példa, amikor egy gomb segítségével lehet kinyitni/becsukni (megjeleníteni/elrejteni) egy másik elemet, például egy szövegblokkot, vagy egy navigációs listát. Ezt a komponenst a képernyőolvasós felhasználók akkor tudják jól működtetni, ha a gombról közvetlenül a kinyitott elemre léphetnek tovább. Ennek legegyszerűbb és legpreferáltabb megoldása az, ha a gombot és az általa vezérelt elemet egymás melletti testvérként helyezzük el a DOM fában.

A következő példában a <ul id="termekeink"> elemmel jelölt navigációs lista közvetlenül az őt vezérlő <button> elem után található. A kód azt az állapotot mutatja, amikor a navigációs lista ki van nyitva (nincs elrejtve). Erre utal a gomb aria-expanded="true" attribútuma.

<nav>
    <button
        type="button"
        aria-expanded="true"
        aria-controls="termekeink">
    Termékeink
    </button>
    <ul id="termekeink">
        <li>
            <a href="/noknek.html">​Nőknek​</a>
        </li>
        <li>
            <a href="/ferfiaknak.html">​Férfiaknak​</a>
        </li>
    </ul>
</nav>

Az ebből létrejövő DOM fában jól látszik, hogy a button és az ul elemek testvérek lettek:

  • nav
    • button
    • ul
      • li
        • a
      • li
        • a

A button szerepű, és a list szerepű objektum testvéri kapcsolata természetesen az akadálymentességi fában is megmarad:

  • navigation
    • button
    • list
      • listitem
        • link
      • listitem
        • link

A látszólagos testvérek problémája

Az akadálymentességi auditok során egyre több olyan kóddal találkozom, amikor az iménti példánkban szereplő gomb, és az általa vezérelt elem között nagyon távoli rokonság van. Lehet, hogy vizuálisan testvérnek látszanak, hiszen a CSS segítségével egymás közelébe vannak pozicionálva, de a kinyitandó elem sokszor valahol a DOM fa legelején vagy legvégén van.

Vázlatosan ezt szemlélteti a következő DOM struktúra, amiben a pontok egyéb elemeket szimbolizálnak:

  • body
    • ...
    • nav
      • button
    • ...
    • ul
      • li
        • a
      • li
        • a

Ez a struktúra a képernyőolvasós felhasználóknak nem akadálymentes, mert a gombról továbblépve nem a navigációs listába jutnak, és a navigációs listát nem a nav elem által definiált navigációs régió részeként hallják. A billentyűzettel navigáló felhasználók számára is problémás, mivel a gombról a TAB billentyű megnyomására nem a navigációs listában lévő első linkre, hanem a gomb utáni első fókuszálható elemre kerülnek.

Megjegyzés: Felmerülhet a kérdés, hogy a button elem aria-controls attribútuma nem arra szolgál, hogy egy akadálymentes kapcsolatot teremtsen a vezérlő és a vezérelt elem között? Még akkor is, ha ezek távol vannak egymástól? A válasz az, hogy igen, viszont ezt a kapcsolatot jelenleg csak a JAWS képernyőolvasó program „kínálja fel”. A JAWS az aria-controls attribútummal rendelkező elemre lépve egy billentyűkombinációt biztosít, aminek megnyomásával a felhasználó közvetlenül a vezérelt elemre ugorhat. De arra már nincs lehetőség, hogy ugyanezt az ugrást visszafele is megtegye. Fontos tudni azt is, hogy az aria-controls a TAB-os fókuszsorrendet abszolút nem befolyásolja, így alkalmazása a billentyűzettel navigáló felhasználóknak sem jelent segítséget.

aria-owns a gyakorlatban

Ennyi alapozás után végre el is érkeztünk a cikk fő témáját adó aria-owns attribútum gyakorlati szerepéhez.

Az aria-owns attribútum segítségével egy elem „örökbefogadhat” olyan elemeket, amelyek a DOM fában nem az ő gyermekei. Másképpen fogalmazva: testvérek lehetnek olyan elemek, amelyek a DOM fában nem testvérek.

Fontos, hogy ez az örökbefogadás kizárólag az akadálymenteségi fában történik meg, vagyis a DOM fa struktúrája ettől nem változik.

A gyakorlatban úgy néz ki, hogy a szülőelem aria-owns attribútumába tudjuk beírni a befogadni kívánt elem id attribútumértékét. Ha több elemet szeretnénk örökbe fogadtatni, akkor szóközzel elválasztva kell felsorolnunk az id azonosítókat, és ezen felsorolás sorrendje lesz a befogadott gyermekek sorrendje.

Amennyiben az adott szülőelemnek a DOM fában már vannak „saját jogú” gyermekei, akkor az akadálymentességi fában előbb ők következnek, és csak utánuk jönnek az aria-owns attribútum által örökbefogadott gyermekek. Érdekesség, hogy az ARIA szabvány elvileg megengedi azt is, hogy az aria-owns attribútumba a saját jogú gyermekek id azonosítói is bekerüljenek. Ezzel a gyermekek sorrendjét lehet beállítani, függetlenül attól, hogy saját jogú gyermekről vagy örökbefogadottról van szó.

Térjünk vissza a legutóbbi példánkhoz, amiben a kinyitható/becsukható navigációs lista és az őt vezérlő gomb a DOM fában nagyon távoli rokonok. Azt szeretnénk elérni, hogy az akadálymentességi fában közvetlen testvérek legyenek, mégpedig úgy, hogy sorrendben a gomb után következzen a navigációs lista. Mivel példánkban a button elem szülője a nav elem, ezért a nav elemet kérjük meg, hogy fogadja örökbe a navigációs listát. Vagyis a nav elem kap egy aria-owns attribútumot, amibe a navigációs lista id attribútumértékét írjuk. A HTML kódunk tehát így nézne ki:

<nav aria-owns="termekeink">
    <button
        type="button"
        aria-expanded="true"
        aria-controls="termekeink">
    Termékeink
    </button>
</nav>
<!-- -->
<!-- itt van egy csomó más elem -->
<!-- -->
<ul id="termekeink">
    <li>
        <a href="/noknek.html">​Nőknek​</a>
    </li>
    <li>
        <a href="/ferfiaknak.html">​Férfiaknak​</a>
    </li>
</ul>

A DOM fában pontosan az a struktúra jön létre, amit korábban is láttunk, vagyis a gomb és a navigációs lista még távol vannak egymástól (a pontok itt is egyéb elemeket szimbolizálnak):

  • ...
    • ...
    • nav
      • button
    • ...
    • ul
      • li
        • a
      • li
        • a

Viszont az aria-owns attribútummal végzett manipulációnk miatt az akadálymentességi fában a navigation szerepű szülőobjektumnak két gyermeke lesz: a saját jogú button, és az örökbefogadott list. Az egyszerűség kedvéért az alábbi ábrán csak az akadálymentességi fa ezen részét emelem ki:

  • navigation
    • button
    • list
      • listitem
        • link
      • listitem
        • link

Ezzel elvileg elértük a célunkat. A képernyőolvasós felhasználók a gombról továbblépve egyből a navigációs listába kerülnek, függetlenül attól, hogy mi a DOM sorrend.

Van azonban egy bökkenő: a megoldásunk ezzel még nem akadálymentes.

A fókuszsorrend sajnos nem változik

A példánkban említett továbblépés csak a képernyőolvasó programok egyedi navigációs billentyűparancsaival (például a billentyűvel), vagy a mobilos képernyőolvasó programok ujjmozdulataival működik helyesen. A továbblépés azokkal a kisegítő technológiákkal is megfelelő lesz, amelyek szintén az akadálymentességi fában lévő objektumsorrendet követik. Ilyenek például a kapcsolóvezérlők.

Ha viszont a képernyőolvasós felhasználók, vagy a billentyűzettel navigáló látó felhasználók a TAB billentyűvel lépnek tovább a gombról, akkor a billentyűfókusz nem az akadálymentességi fa objektumsorrendjét, hanem a DOM fa által meghatározott fókuszsorrendet követi. Ezen felhasználók nem a navigációs listában lévő első linkre kerülnek (ahogy az logikus lenne), hanem a gomb utáni első fókuszálható elemre.

Fontos tehát megjegyeznünk, hogy az aria-owns attribútum a TAB-os fókuszsorrendet egyáltalán nem módosítja.

Az aria-owns alkalmazásakor a billentyűfókusz helyes (logikus sorrendű) mozgását nekünk kell leprogramoznunk JavaScript-ben, ami nem feltétlenül egy triviális feladat. Ráadásul egy hibás implementáció egyéb akadálymentességi problémákat is okozhat. Egyesekben felmerülhet a tabindex attribútum alkalmazása, de erről mindenkit lebeszélnék. Ugyanakkor a konkrét feladattól függően a popover és a popovertarget attribútumok használata esetleg szóba jöhet. Ezeknél ugyanis a böngésző saját maga kezeli le a billentyűfókusz logikus sorrendjét. (Érdekesség, hogy a kisegítő technológiák általi logikus bejárást viszont nem. De ezt majd talán egy másik cikkben fogom tárgyalni.)

A fókuszsorrendből adódó nehézségek is megerősítik azt az alapelvet, hogy csak utolsó lehetőségként használjuk az aria-owns attribútumot. Mindenki számára jobb, ha inkább a DOM fában valósítjuk meg a kívánt elemsorrendet.

Mire vigyázzunk még?

A HTML és az ARIA szabványok pontosan specifikálják, hogy egy elemnek lehetnek-e gyermekei, és ha igen, akkor milyen típusúak (szerepűek). Például az img elemnek nem lehet gyermeke, vagy a button elemnek nem lehet interaktív gyermeke. Figyelnünk kell tehát arra, hogy ezeket a követelményeket az aria-owns attribútum használatakor is betartsuk.

Érdekesség, hogy ez a probléma okozta az ARIA 1.0 szabványban specifikált kombinált listamező (combobox szerep) „vesztét” is. Abban ugyanis az szerepelt, hogy a <input type="text"> role="combobox"> elem az aria-owns attribútum segítségével fogadja örökbe a listbox szereppel rendelkező választólistát. Mivel azonban a HTML szabvány szerint az input elemnek nem lehet gyermeke, ezért sok böngészőprogram nem hozta létre a kívánt szülő-gyerek kapcsolatot az akadálymentességi fában. Nem véletlen, hogy az ARIA szabvány jelenlegi verziójában a combobox szereppel rendelkező input elem már nem befogadja, hanem az aria-controls attribútum segítségével csak vezérli a választólistát.

A másik dolog amire vigyáznunk kell, hogy egy elemnek csak egy szülője lehet. Vagyis egy elem id azonosítója soha ne szerepeljen egyszerre több másik elem aria-owns attribútumában. Körkörös hivatkozásokat sem szabad kialakítani.

Milyen támogatottsága van?

Az aria-owns tulajdonság (attribútum) már a 2014-ben kiadott ARIA 1.0 szabványban is szerepelt, de a böngészőprogramok csak jóval később, és csak szakaszosan kezdték el támogatni. Ez is volt az oka annak, hogy a gyakorlatban eddig nem sokan alkalmazták. Jelenleg már minden modern böngészőprogramban használható, és a kisegítő technológiák is jól átveszik. Ez persze nem jelenti azt, hogy az aria-owns attribútumra épülő implementációnkat ne kellene alaposan letesztelni a lehető legtöbb böngésző és kisegítő technológia párossal.