A 04-01 vam fixar la regla d'or: fes servir l'element HTML natiu abans de recrear-lo. A 04-02 ja vam apuntar atributs com aria-describedby, aria-invalid i role="alert". Ara toca entendre què són aquests atributs: WAI-ARIA (Accessible Rich Internet Applications), un conjunt d'atributs que permeten descriure semàntica —rol, estat i propietats— en el marcatge quan l'HTML natiu no hi arriba. ARIA no canvia el que veu l'usuari ni afegeix comportament: només canvia el que exposa l'arbre d'accessibilitat que vam estudiar al Mòdul 2. És una capa d'informació, no d'interacció.
Precisament per això, aquesta lliçó tracta ARIA com a semàntica declarativa: com etiquetar rols i estats en l'HTML. Construir el widget interactiu —capturar teclat, moure el focus i actualitzar aquests estats amb JavaScript— és el Mòdul 5 (05-01). Aquí veuràs, per exemple, com donar a la Marta el name/role/value correcte del desplegable de filtres de Cursalia; fer que funcioni amb el teclat serà el mòdul següent.
Contingut
- Què és ARIA i què no és
- Les 5 regles de l'ARIA
- Rols: landmark, widget i document
- Estats i propietats
- El nom accessible:
aria-label,aria-labelledby,aria-describedby aria-hiddeni el perill d'amagar contingut focusable- Introducció a les live regions
- Cas Cursalia: name/role/value del desplegable de filtres
- Taula d'atributs ARIA freqüents
- Errors comuns i consells
- Exercicis
- Conclusió
Què és ARIA i què no és
ARIA aporta tres tipus d'informació a l'arbre d'accessibilitat:
- Rols (
role="..."): què és un element (un botó, una pestanya, una alerta). - Propietats (
aria-label,aria-describedby...): característiques relativament estables. - Estats (
aria-expanded,aria-checked...): condicions que canvien amb la interacció.
El que ARIA NO fa, i convé gravar-s'ho:
- No afegeix comportament.
role="button"en un<div>no el fa clicable amb teclat ni focusable; només diu que és un botó. El comportament l'hi poses tu amb JS (Mòdul 5). - No canvia l'aparença. No aplica estils.
- No millora res per si sol. Un ARIA mal posat és pitjor que no posar-ne cap, perquè menteix al lector de pantalla.
"Cap ARIA és millor que un mal ARIA." Un
aria-*incorrecte crea una experiència trencada i difícil de diagnosticar.
Les 5 regles de l'ARIA
L'especificació resumeix el bon ús de l'ARIA en cinc regles. Són la brúixola d'aquesta lliçó.
- Si pots fer servir un element HTML natiu amb la semàntica i el comportament que necessites, fes-lo servir, i no facis servir ARIA. Un
<button>abans que un<div role="button">. És la regla d'or de 04-01. - No canviïs la semàntica nativa llevat que sigui imprescindible. No facis
<h2 role="button">; embolcalla el text en un<button>dins de l'<h2>. Canviar el rol natiu esborra l'original (el "heading" desapareix). - Tot widget ARIA interactiu ha de ser operable amb el teclat. Si crees
role="button", ha de rebre focus i activar-se amb Enter/Espai. (La implementació és del Mòdul 5, però la regla neix aquí.) - No posis
role="presentation"niaria-hidden="true"en elements focusables. Amagaries de l'arbre alguna cosa que el teclat sí que pot assolir: l'usuari enfoca "el no-res". - Tot element interactiu ha de tenir un nom accessible. Un botó sense nom ("botó, sense etiqueta") és inservible per a la Marta.
graph TD
A["Necessito semàntica extra?"] --> B{"Existeix un element<br/>HTML natiu?"}
B -->|"Sí"| C["Fes-lo servir. NO facis servir ARIA<br/>(Regla 1)"]
B -->|"No"| D["Fes servir ARIA:<br/>rol + estats + nom"]
D --> E["Fes-lo operable per teclat<br/>(Regla 3 → Mòdul 5)"]
Rols: landmark, widget i document
Els rols ARIA s'agrupen en famílies. Tres importen aquí:
- Rols de landmark: regions de navegació. Ja els obtens gratis amb HTML5 (
<nav>=navigation,<main>=main...). Només faries servir l'ARIA equivalent (role="navigation") si no pots emprar l'element natiu. - Rols de widget: components interactius (
button,checkbox,tab,menuitem,dialog,slider...). Descriuen controls rics. Construir-ne el comportament és el Mòdul 5; aquí només declarem el rol. - Rols de document/estructura: organitzen contingut (
list,listitem,heading,article,alert,status...).
| Tipus d'element HTML5 | Rol implícit (no cal declarar-lo) |
|---|---|
<nav> |
navigation |
<main> |
main |
<button> |
button |
<ul> / <li> |
list / listitem |
<h1>–<h6> |
heading (amb el seu nivell) |
La lliçó: si l'element natiu ja té el rol, no el repeteixis amb role. <nav role="navigation"> és redundant.
Estats i propietats
Quan l'HTML natiu no pot expressar un estat (perquè el control no existeix de forma nativa), ARIA el comunica. Els més freqüents en marcatge declaratiu:
| Atribut | Què comunica | Valors típics |
|---|---|---|
aria-expanded |
Si un desplegable/acordió està obert | true / false |
aria-checked |
Estat d'un checkbox/radio personalitzat | true / false / mixed |
aria-selected |
Element seleccionat (pestanyes, llistes) | true / false |
aria-disabled |
Deshabilitat (però encara perceptible pel lector) | true / false |
aria-current |
L'element actual dins d'un conjunt | page, step, true... |
aria-pressed |
Estat d'un botó d'alternança | true / false |
Un exemple declaratiu: a la barra de navegació de Cursalia, marcar la pàgina actual amb aria-current="page" perquè la Marta sàpiga on és.
<!-- CORRECTE: aria-current assenyala la pàgina activa -->
<nav aria-label="Principal">
<ul>
<li><a href="/cursos" aria-current="page">Catàleg</a></li>
<li><a href="/preus">Preus</a></li>
</ul>
</nav>Advertència clau: aquests estats són declaracions. aria-expanded="false" al botó de filtres només diu "tancat"; actualitzar-lo a true en obrir és feina de JavaScript (Mòdul 5). Un estat que mai no s'actualitza torna a mentir al lector.
El nom accessible: aria-label, aria-labelledby, aria-describedby
El nom accessible és el text que el lector anuncia per identificar un element (el name de name/role/value). El navegador el calcula seguint una prioritat. Simplificada, de major a menor:
aria-labelledby(apunta alsidd'altres elements que serveixen de nom). Guanya sobre tota la resta.aria-label(text literal en el mateix atribut).- El contingut/label natiu (el text del
<button>, el<label for>associat). - Altres mecanismes (
title...), com a últim recurs.
aria-label: dona un nom quan no hi ha text visible. Ideal per al botó de tancar (una "X") o el cercador amb només una lupa.
<!-- CORRECTE: sense text visible, aria-label dona el nom -->
<button type="button" aria-label="Tanca el panell de filtres">✕</button>aria-labelledby: construeix el nom a partir de text ja visible a la pàgina (evita duplicar i traduir dues vegades). Pot referenciar diversosid, que es concatenen.
<!-- CORRECTE: el nom de la regió es pren del seu encapçalament visible -->
<section aria-labelledby="tit-filtres">
<h2 id="tit-filtres">Filtra cursos</h2>
...
</section>aria-describedby: no aporta el nom sinó una descripció addicional (es llegeix després). És el que fem servir a 04-02 per a ajudes i errors de formulari.
Diferència essencial: labelledby = com es diu; describedby = informació extra. I aria-labelledby sobreescriu el text intern, així que fes-lo servir amb cura.
aria-hidden i el perill d'amagar contingut focusable
aria-hidden="true" elimina un element (i els seus descendents) de l'arbre d'accessibilitat, sense amagar-lo visualment. Serveix per amagar del lector coses purament decoratives o duplicades: una icona al costat d'un text que ja ho diu.
<!-- CORRECTE: la icona és decorativa; el text ja comunica l'acció -->
<button type="button">
<span aria-hidden="true">🔍</span> Cerca
</button>L'error greu (Regla 4) és posar aria-hidden="true" en alguna cosa focusable o que contingui elements focusables (un enllaç, un botó, un input). El resultat: la Lucía tabula fins a un control que el lector considera inexistent. Enfoca "el no-res".
<!-- INCORRECTE: s'amaga del lector un enllaç que segueix sent focusable -->
<a href="/ajuda" aria-hidden="true">Ajuda</a>Si de debò vols retirar alguna cosa del tot (visual i de l'arbre), fes servir hidden, display:none o treu-la del DOM; aria-hidden només afecta l'arbre, no el focus.
Introducció a les live regions
Una live region és una zona el contingut de la qual, quan canvia dinàmicament, el lector anuncia sol, sense que l'usuari hagi d'anar-hi fins allà. És la base del criteri 4.1.3 (Missatges d'estat) que vam veure com a requisit al Mòdul 3. A nivell de marcatge hi ha tres peces:
aria-live="polite": anuncia quan el lector acabi el que estava dient. Per a missatges no urgents: "Filtre aplicat: 12 cursos".aria-live="assertive": interromp i anuncia de seguida. Per al que és urgent: un error d'enviament.- Rols drecera:
role="status"equival apolite;role="alert"equival aassertive.
<!-- CORRECTE: regió educada per confirmar resultats del filtre -->
<div role="status" aria-live="polite" id="resultat-filtre"></div>// El lector anunciarà aquest text tan aviat com el teu JS l'escrigui:
document.getElementById('resultat-filtre').textContent =
'Filtre aplicat: 12 cursos trobats.';Punt important: el contenidor ha d'existir buit en el DOM des del principi; el lector vigila els canvis dins d'ell. Ens quedem en el marcatge. El detall del comportament dinàmic, quan fer servir polite vs assertive en formularis validats en viu i el testing corresponen als Mòduls 5, 6 i 7.
Cas Cursalia: name/role/value del desplegable de filtres
Cursalia té un botó "Filtres" que mostra o amaga un panell. Suposem —seguint la regla 1— que no podem fer servir <details>/<summary> natius i cal construir-lo. La nostra tasca en aquest mòdul és només el marcatge semàntic correcte perquè la Marta percebi què és i en quin estat està:
<!-- Semàntica declarativa: rol (button, natiu), nom (text) i estat (aria-expanded) -->
<button type="button"
aria-expanded="false"
aria-controls="panell-filtres">
Filtres
</button>
<div id="panell-filtres" hidden>
<h2>Filtra cursos</h2>
<!-- checkboxes de categoria, nivell, idioma... -->
</div>Analitzem què rep la Marta:
- Role:
button(natiu, no cal ARIA per al rol). - Name: "Filtres" (text del botó).
- Value/State:
aria-expanded="false"→ el lector anuncia "contret". aria-controls="panell-filtres": declara quin element governa el botó.
Amb això, la Marta sent: "Filtres, botó contret". Sap què és, com es diu i el seu estat.
El que falta i NO és d'aquest mòdul: que en prémer es mostri el panell, que aria-expanded passi a true, que es retiri el hidden, i que el teclat (Enter/Espai/Escape) funcioni. Tot aquest comportament és 05-01/05-02. Aquí hem deixat la bastida semàntica perfecta perquè aquest JavaScript només hagi d'actualitzar l'estat.
Taula d'atributs ARIA freqüents
| Atribut | Categoria | Per a què serveix |
|---|---|---|
role |
— | Declara què és l'element (si no hi ha natiu) |
aria-label |
Propietat | Nom per text literal (sense text visible) |
aria-labelledby |
Propietat | Nom pres d'altres elements visibles |
aria-describedby |
Propietat | Descripció addicional (ajudes, errors) |
aria-expanded |
Estat | Obert/tancat de desplegables i acordions |
aria-controls |
Propietat | Quin element controla aquest control |
aria-current |
Estat | Element actual (pàgina, pas) |
aria-selected |
Estat | Element seleccionat (pestanyes, opcions) |
aria-checked |
Estat | Marcat de checkbox/radio personalitzat |
aria-disabled |
Estat | Deshabilitat però perceptible |
aria-hidden |
Propietat | Amaga de l'arbre (mai en focusables!) |
aria-live |
Propietat | Regió que s'anuncia en canviar |
Errors Comuns i Consells
- Reinventar amb ARIA el que ja existeix.
<div role="button">en lloc de<button>. Regla 1 sempre primer. - Sobreescriure la semàntica nativa.
<a role="button">o<h2 role="tab">esborren el rol original. Gairebé mai és el que vols. - Estats que no s'actualitzen. Un
aria-expanded="false"que mai no canvia menteix. Si poses l'estat, alguna cosa (JS, Mòdul 5) l'ha de mantenir al dia. aria-hiddensobre elements focusables. Crea "trampes" on el focus existeix però el lector no veu res.- Elements interactius sense nom. Un botó-icona sense
aria-labelés "botó sense etiqueta". Regla 5. - Confondre
labelledbyambdescribedby. El primer és el nom; el segon, informació extra que es llegeix després. - Live region creada en el moment del canvi. Ha d'existir buida des de l'inici perquè el lector la vigili.
- Consell: valida el teu ARIA amb la vista d'arbre d'accessibilitat del navegador (DevTools) i amb un lector real. Si dubtes si afegir un
aria-*, probablement la resposta sigui fer servir HTML natiu.
Exercicis
Exercici 1: aplicar la regla 1
Un company ha maquetat el botó de reproduir de la vídeo-lliçó així. Reescriu-lo complint les regles de l'ARIA.
Exercici 2: donar nom accessible
El botó de tancar el panell de filtres només mostra una icona "✕" i no té text. Dona-li un nom accessible sense afegir text visible, i explica quin mecanisme fas servir.
Exercici 3: name/role/value d'un acordió de FAQ
Cursalia té una pregunta freqüent plegable. Escriu només el marcatge semàntic (rol, nom i estat) de l'encapçalament que obre/tanca la resposta, indicant quina part queda per al Mòdul 5.
Solucions
Solució 1. La regla 1 diu: fes servir l'element natiu. Un <button> dona rol, focus i teclat gratis, sense tabindex ni gestors manuals de teclat; la icona es marca decorativa i s'afegeix un nom:
<button type="button" aria-label="Reprodueix la lliçó" onclick="play()">
<span aria-hidden="true">▶</span>
</button>Així complim les regles 1 (natiu), 3 (operable amb teclat, gratis) i 5 (té nom).
Solució 2. Com que no hi ha text visible, es fa servir aria-label (propietat que dona un nom per text literal). La icona s'amaga del lector perquè és decorativa:
<button type="button" aria-label="Tanca el panell de filtres">
<span aria-hidden="true">✕</span>
</button>Si el nom ja estigués escrit visiblement en un altre element, l'opció preferent seria aria-labelledby apuntant-hi.
Solució 3. El patró accessible embolcalla el text de la pregunta en un <button> dins de l'encapçalament (no es canvia el rol de l'<h3>; regla 2):
<h3>
<button type="button" aria-expanded="false" aria-controls="resp-1">
Puc pausar la meva subscripció?
</button>
</h3>
<div id="resp-1" hidden>
<p>Sí, des del teu panell d'alumne pots pausar-la en qualsevol moment.</p>
</div>- Role:
button(natiu) dins d'unheadingque es conserva. - Name: el text de la pregunta.
- State:
aria-expanded="false".
El que queda per a 05-01: mostrar/amagar #resp-1, alternar aria-expanded i gestionar el teclat. Aquí només deixem la semàntica a punt.
Conclusió
ARIA és la manera d'afegir semàntica —rol, estat i nom— en el marcatge quan l'HTML natiu no basta, però la seva primera regla és no fer-lo servir si hi ha una alternativa nativa, i un ARIA mal posat és pitjor que cap. Has vist les cinc regles, els tipus de rol, els estats declaratius com aria-expanded, com es calcula el nom accessible (amb la prioritat labelledby > label > text natiu), el perill d'aria-hidden sobre focusables i una introducció a les live regions. I has deixat el desplegable de filtres de Cursalia amb un name/role/value impecable, a punt perquè el Mòdul 5 li doni comportament.
Ens queda una peça del principi "Perceptible" que encara no hem implementat i que és pur CSS: que el contingut es vegi i es llegeixi bé. A 04-04 · Contrast de Color i Redimensionament de Text tancarem el mòdul amb ratios de contrast, no dependre del color, unitats relatives, reflow i focus visible, aplicats a la paleta de marca de Cursalia i a la Sofía amb el seu zoom al 300%.
Curs d'Accessibilitat Web
Mòdul 1: Introducció a l'Accessibilitat Web
- Què és l'Accessibilitat Web?
- La Importància de l'Accessibilitat Web
- Visió General de les Lleis i Normes d'Accessibilitat
- Introducció a les WCAG
Mòdul 2: Comprensió de les Discapacitats i les Tecnologies d'Assistència
- Tipus de Discapacitats
- Visió General de les Tecnologies d'Assistència
- Com Utilitzen la Web les Persones amb Discapacitat
Mòdul 3: Principis del Disseny Accessible
- Perceptible: Fer el Contingut Disponible als Sentits
- Operable: Interfície d'Usuari i Navegació
- Comprensible: Informació i Operació
- Robust: Compatibilitat amb Tecnologies Actuals i Futures
Mòdul 4: Implementació de l'Accessibilitat en HTML i CSS
- HTML Semàntic
- Formularis Accessibles
- Ús de Rols i Propietats ARIA
- Contrast de Color i Redimensionament del Text
Mòdul 5: Accessibilitat en JavaScript i Multimèdia
- Creació de Widgets de JavaScript Accessibles
- Accessibilitat del Teclat
- Contingut de Vídeo i Àudio Accessible
- Proporcionar Alternatives de Text per a les Imatges
Mòdul 6: Proves i Avaluació de l'Accessibilitat
- Tècniques de Proves Manuals
- Eines de Proves Automatitzades
- Proves d'Usuari amb Tecnologies d'Assistència
- Interpretació d'Informes d'Accessibilitat
