Addaw, anar a la pàgina d'inici Donar

Lliçó 10 de 10 · Cas pràctic · 25 min · Revisada el 26/10/2026

Cas pràctic, exercicis i llista de comprovació

Estàs llegint una lliçó oberta. Matricula't gratis per fer els tests i els exercicis, desar el teu progrés i aconseguir el certificat.

Aquesta lliçó reuneix tot el curs en un cas realista. Primer resolem pas a pas la revisió d'un component amb problemes d'ARIA; després practiques amb exercicis d'autoavaluació i acabes amb una llista de comprovació que pots fer servir en la teva feina.

El cas: la cita prèvia d'una seu electrònica

Un ajuntament ha renovat el formulari de cita prèvia de la seva seu electrònica. La persona tria oficina, filtra les franges disponibles i confirma la cita. Una veïna que fa servir NVDA amb Firefox ha enviat una queixa a través del mecanisme de comunicació que exigeix l'RD 1112/2018 (PDF, s'obre en una finestra nova): «No puc obrir els filtres, no sé quantes cites hi ha i, després de tancar l'avís de la galeta, la pàgina es queda muda». Aquest és el fragment rellevant:

<div class="btn-filtros" role="button" onclick="toggleFiltros()">Filtres</div>
<div id="filtros" class="oculto">
  <span class="switch" onclick="toggleTardes(this)">Només tardes</span>
</div>
<p class="contador">12 franges disponibles</p>
<div role="option" class="hueco" onclick="elegir(this)">Dilluns 3, 17:00</div>
<div role="option" class="hueco" onclick="elegir(this)">Dilluns 3, 17:30</div>
<button aria-label="Close" onclick="cerrarAviso()"><svg>…</svg></button>
<button disabled>Confirma la cita</button>
<main aria-hidden="true">…</main> <!-- estat després de tancar l'avís -->

Pas 1: inventari

Busca al codi totes les aparicions de role= i aria-, i tots els controls construïts amb elements genèrics i onclick. Aquí hi ha sis peces per revisar: el botó de filtres, l'interruptor, el comptador, les opcions d'hora, el botó de tancar l'avís i el botó de confirmar, més l'estat de <main> després de tancar l'avís.

Pas 2: inspeccionar l'arbre i escoltar

Amb el panell Accessibilitat del navegador i NVDA (amb el Visualitzador de veu actiu), recorre el formulari amb Tab i amb el mode d'exploració. Troballes:

  • El div de filtres s'anuncia com a botó en mode d'exploració, però Tab no hi arriba mai i no respon a Retorn (regles 1 i 3). Tampoc no comunica si el panell està obert.
  • L'interruptor és un span sense rol ni estat: el lector diu «Només tardes» com a text pla (4.1.2).
  • En filtrar, el comptador canvia de 12 a 4 sense anunciar-se (4.1.3).
  • Les opcions estan soltes, sense cap listbox que les contingui ni teclat, i no indiquen quina està triada.
  • El botó de tancar es diu «Close» en una pàgina en català, i la icona no està amagada.
  • «Confirma la cita» està inhabilitat i ningú que navegui amb teclat no sap per què.
  • <main> conserva aria-hidden="true" després de tancar l'avís: tot el contingut ha desaparegut per al lector, tot i que el focus continua arribant als controls.

Pas 3: corregir, del més greu al menys greu

Primer el que bloqueja completament: el contingut amagat. L'avís es refà amb inert (o amb <dialog>), i es comprova que en tancar-lo es restaura l'estat. Després, els controls: HTML natiu sempre que existeix i ARIA només per al que l'HTML no expressa. Finalment, els anuncis.

<button type="button" aria-expanded="false" aria-controls="filtros">Filtres</button>
<div id="filtros" hidden>
  <button type="button" role="switch" aria-checked="false">Només tardes</button>
</div>
<p role="status" id="contador"></p>
<fieldset>
  <legend>Hora de la cita</legend>
  <label><input type="radio" name="hora" value="1700"> Dilluns 3, 17:00</label>
  <label><input type="radio" name="hora" value="1730"> Dilluns 3, 17:30</label>
</fieldset>
<button type="button" aria-label="Tanca l'avís"><svg aria-hidden="true">…</svg></button>
<button type="submit" aria-disabled="true" aria-describedby="motivo">Confirma la cita</button>
<p id="motivo">Tria una hora per continuar.</p>

Decisions explicades:

  • Les opcions d'hora no necessitaven un listbox: són una elecció única entre diverses, i els botons d'opció natius dins d'un fieldset donen rol, estat, agrupació i teclat sense una línia d'ARIA (regla 1).
  • L'interruptor sí que fa servir ARIA, perquè l'HTML no té un interruptor natiu: role="switch" sobre un <button>, amb aria-checked actualitzat per JavaScript i el CSS depenent de l'atribut.
  • El comptador és una regió status que existeix buida en carregar; l'script hi escriu «4 franges disponibles» després de cada filtre.
  • El nom «Tanca l'avís» està en català i coincideix amb el que fa (2.5.3 no s'aplica perquè no hi ha text visible, però l'idioma sí que importa).
  • «Confirma la cita» es manté descobrible amb aria-disabled i n'explica el motiu; l'script bloqueja l'enviament mentre falti l'hora. Una alternativa igual de vàlida és deixar-lo actiu i mostrar un error en prémer-lo.

Pas 4: verificar

Es repeteix el recorregut amb NVDA i Firefox i amb VoiceOver i Safari: «Filtres, botó, contret» i «expandit» en prémer-lo; «Només tardes, interruptor, desactivat»; «4 franges disponibles» sense moure el focus; les hores com a grup de botons d'opció; «Confirma la cita, botó, no disponible, Tria una hora per continuar». Es passen axe i el validador del W3C per confirmar que no queden referències trencades ni atributs no vàlids, i es respon a la veïna amb la correcció feta.

Exercicis d'autoavaluació

1. Una casella d'acceptació està feta així: <div role="checkbox" aria-checked="false" tabindex="0">Accepto les condicions</div>. Què li falta i quina és la millor solució?

Mostra la solució

Li falta el comportament: respondre a Espai i actualitzar aria-checked a cada canvi, a més de participar en l'enviament del formulari. La millor solució és la regla 1: <input type="checkbox"> amb el seu <label>, que dona tot això sense ARIA.

2. A l'enllaç «Mostra tots els tràmits →» el lector anuncia «fletxa dreta». Com ho evites sense canviar l'aspecte?

Mostra la solució

Embolcalla la fletxa en un <span aria-hidden="true">. L'enllaç continua sent enfocable i conserva el nom «Mostra tots els tràmits»; només es retira de l'arbre l'adorn.

3. Un llistat de resultats virtualitzat mostra 20 de 300 elements i el lector anuncia «1 de 20» al resultat número 141. Quins atributs ho corregeixen?

Mostra la solució

aria-setsize="300" i aria-posinset="141" (i successius) a cada element de la llista, juntament amb un text visible del tipus «Es mostren 141-160 de 300». Comprova'n el suport amb els lectors del teu públic.

4. Una intranet posa role="application" al <body> perquè funcionin les seves dreceres d'una sola tecla. Quina conseqüència té i què proposes?

Mostra la solució

El lector deixa d'interceptar el teclat a tota la pàgina: la persona no pot llegir amb fletxes ni saltar per encapçalaments. Cal treure el rol i revisar les dreceres perquè es puguin desactivar o reassignar, o actuïn només amb el focus al component, com exigeix 2.1.4 Dreceres de teclat.

5. La navegació principal d'un portal fa servir <ul role="menu"> amb role="menuitem" a cada enllaç. Què canviaries?

Mostra la solució

Trauria els rols menu i menuitem, pensats per a menús d'aplicació operats amb fletxes, i faria servir <nav aria-label="Principal"> amb una llista d'enllaços normals, marcant la pàgina actual amb aria-current="page".

Llista de comprovació

  • He fet servir HTML natiu sempre que hi havia un element equivalent.
  • No hi ha rols redundants, no vàlids ni abstractes.
  • Cada rol de giny té focus i el teclat que descriu l'APG (s'obre en una finestra nova).
  • Cada rol respecta el seu context i els seus fills obligatoris.
  • Tots els controls tenen un nom accessible que conté el text visible.
  • Cada estat visual té el seu atribut ARIA, i JavaScript l'actualitza.
  • Totes les referències per id existeixen i són úniques.
  • No hi ha aria-hidden="true" sobre elements enfocables ni a <body>.
  • Les zones fora d'ús fan servir inert, i es restauren en acabar.
  • Els controls amb aria-disabled bloquegen l'acció i n'expliquen el motiu.
  • Els missatges d'estat s'escriuen en regions status o alert que ja existien buides.
  • No hi ha role="application" llevat de superfícies amb teclat propi complet.
  • He passat axe i el validador del W3C sense errors d'ARIA.
  • He escoltat cada component amb almenys dos lectors de pantalla.

Per continuar aprenent

T'ha servit aquesta lliçó?

Crea el teu compte gratis i segueix el curs amb tot:

  • El test d'aquesta lliçó (3 preguntes) per comprovar el que has après
  • Exercicis pràctics amb pàgines reals
  • El teu progrés desat: continues on ho vas deixar, des de qualsevol dispositiu
  • Constància del curs amb les hores i certificat gratuït del nivell 3 quan aprovis l'examen

Entres amb el teu compte de Google o només amb el teu correu electrònic. No cal contrasenya.