Lliçó 6 de 10 · 14 min de lectura · Revisada el 26/10/2026
JavaScript accessible: esdeveniments, canvis de context, límits de temps i contingut dinàmic
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.
L'HTML aporta la semàntica i el CSS la presentació; el JavaScript decideix què passa i quan. Aquí apareixen problemes que cap etiqueta no corregeix: accions que es disparen en prémer en lloc d'en deixar anar, desplegables que canvien de pàgina sense avisar, sessions que caduquen enmig d'un tràmit i contingut que se substitueix i s'emporta el focus per davant. Aquesta lliçó reuneix els criteris que depenen del comportament programat (2.5.2 Cancel·lació del punter, 3.2.1 En rebre el focus, 3.2.2 En introduir dades i 2.2.1 Temps ajustable) i les tècniques per gestionar el contingut que apareix i desapareix. És la base de la lliçó següent, en què veuràs com s'aplica tot això a les aplicacions d'una sola pàgina.
Esdeveniments: escolta la intenció, no el dispositiu
L'esdeveniment click d'un element natiu és el més inclusiu que existeix: es dispara amb el ratolí, amb un toc a la pantalla, amb Retorn o la barra espaiadora, amb el control per veu, amb un commutador i amb els gestos d'activació dels lectors de pantalla. Per això un <button> amb un gestor click no necessita res més per ser operable.
Els esdeveniments de baix nivell (mousedown, pointerdown, touchstart) són una altra història. 2.5.2 Cancel·lació del punter (A) exigeix que, per a la funcionalitat que es fa servir amb un sol punter, es compleixi almenys una d'aquestes condicions: que no s'executi res en prémer (esdeveniment descendent); que l'acció es completi en deixar anar i es pugui avortar apartant el punter abans de deixar anar, o desfer després; que en deixar anar es reverteixi el que va fer el prémer; o que actuar en prémer sigui essencial (les tecles d'un piano virtual). Es tracta de poder fer-se enrere, cosa vital per a qui té tremolors.
Exemple
// Incorrecte: esborra tan bon punt es prem, sense possibilitat de cancel·lar,
// i no funciona amb teclat
filaBorrar.addEventListener('mousedown', () => eliminarExpediente(id));
// Correcte: click es dispara en deixar anar (i amb teclat); si el punter
// surt del botó abans de deixar anar, no passa res
botonBorrar.addEventListener('click', () => eliminarExpediente(id));
L'arrossegar i deixar anar és el cas legítim de prémer per «agafar»: compleix perquè l'acció es completa en deixar anar i es cancel·la deixant anar fora de la destinació. Tot i així necessita una alternativa sense arrossegament, com vas veure amb 2.5.7 Moviments d'arrossegament en el curs de components.
Altres regles per als gestors d'esdeveniments:
- Si programes el teclat per a un control personalitzat, fes servir
keydowni la propietatevent.key('Enter',' ','Escape','ArrowDown');keypressikeyCodeestan obsolets. - No capturis tecles de manera global sense necessitat: els lectors de pantalla i les extensions en fan servir moltes. Si afegeixes dreceres d'una sola tecla, s'han de poder desactivar o reassignar, o funcionar només amb el focus al component (2.1.4 Dreceres de teclat, vist en el curs de teclat).
- Tot el que facis amb
mouseenteromouseoverha de tenir el seu equivalent ambfocusofocusin.
Canvis de context: 3.2.1 i 3.2.2
Les WCAG distingeixen entre canvi de contingut i canvi de context. Un canvi de context és un canvi important que, si es produeix sense que la persona l'esperi, la desorienta: obrir una finestra nova, navegar a una altra pàgina, moure el focus a un altre lloc o canviar el contingut de manera que canviï el sentit de la pàgina. Filtrar una llista de resultats dins de la mateixa pàgina és un canvi de contingut; portar-te a una altra pàgina, un canvi de context.
- 3.2.1 En rebre el focus (A): que un element rebi el focus no ha de provocar un canvi de context. Errors típics: obrir una finestra emergent en enfocar un camp, enviar un formulari en arribar a un botó, fer saltar el focus a un altre lloc en tabular.
- 3.2.2 En introduir dades (A): canviar el valor d'un control (triar una opció, marcar una casella, escriure) no ha de provocar automàticament un canvi de context, tret que s'hagi avisat abans.
Error freqüent
<!-- Incorrecte: triar una opció navega immediatament -->
<label for="idioma">Idioma</label>
<select id="idioma" onchange="location.href = this.value">…</select>
<!-- Correcte: la persona tria i confirma -->
<form action="/cambiar-idioma">
<label for="idioma">Idioma</label>
<select id="idioma" name="idioma">…</select>
<button type="submit">Canvia l'idioma</button>
</form>
En molts navegadors, amb teclat, en recórrer les opcions d'un select tancat amb les fletxes cada opció dispara change: qui volia passar de «Castellà» a «Valencià» acaba a «Català» sense haver-ho triat. El mateix passa amb el formulari que s'envia sol en escriure l'últim dígit d'un codi.
Avisar abans («En triar una província es carregarà la pàgina de la seva delegació») fa que es compleixi el criteri, però la solució més sòlida és que la persona confirmi amb un botó. Els canvis de contingut sí que poden ser immediats; només cal comunicar-los, per exemple escrivint «23 resultats» en una regió role="status", com vas veure en el curs d'ARIA.
Límits de temps: sessions que caduquen
Les seus electròniques, la banca en línia i les passarel·les de pagament tanquen la sessió per inactivitat. És legítim, però 2.2.1 Temps ajustable (A) exigeix que, per a cada límit de temps, es compleixi almenys una opció: que la persona el pugui desactivar; que el pugui ajustar a com a mínim deu vegades la seva durada; o que rebi un avís abans que expiri, disposi d'almenys 20 segons per allargar-lo amb una acció senzilla (per exemple, prémer una tecla) i el pugui allargar almenys deu vegades. En queden exceptuats els esdeveniments en temps real (una subhasta), els límits essencials (un examen cronometrat) i els que superen les 20 hores.
Qui fa servir un commutador o un lector de pantalla, o necessita més temps per llegir, pot trigar diverses vegades més. Una implementació per a una sessió de 15 minuts:
const DURACION = 15 * 60 * 1000;
const AVISO_ANTES = 2 * 60 * 1000;
let temporizador;
function programarAviso() {
clearTimeout(temporizador);
temporizador = setTimeout(mostrarAviso, DURACION - AVISO_ANTES);
}
function mostrarAviso() {
// Diàleg modal (role="alertdialog") amb el focus a «Allarga la sessió»
dialogoSesion.showModal();
botonAmpliar.focus();
}
botonAmpliar.addEventListener('click', async () => {
await renovarSesionEnServidor();
dialogoSesion.close();
programarAviso();
});
Dos complements AAA que marquen la diferència en tràmits llargs: 2.2.5 Reautenticació (si la sessió caduca, en tornar a identificar-se es continua sense perdre dades) i 2.2.6 Límits de temps (avisar de quanta inactivitat provoca la pèrdua de dades, tret que es conservin més de 20 hores). Desar un esborrany del formulari ajuda a complir tots dos i evita perdre mitja hora de feina.
Contingut que apareix, desapareix o se substitueix
Cada vegada que el JavaScript modifica el DOM cal preguntar-se dues coses: on queda el focus i com se n'assabenta qui no veu la pantalla.
- Insereix el contingut nou just després del seu disparador en el DOM: el panell d'un acordió, el text de «Mostra'n més», els camps que apareixen en marcar una opció. Així el Tab següent hi arriba. Si l'afegeixes al final del
body, ningú no el trobarà. - Botó «Carrega'n més»: després de carregar, mou el focus al primer element nou o deixa el focus al botó i anuncia «10 resultats més carregats» en una regió d'estat.
- Element eliminat: si l'element que tenia el focus desapareix (la fila que s'acaba d'esborrar, el botó que se substitueix per un altre), el focus cau al
bodyi la persona torna al principi de la pàgina. Mou el focus a un lloc lògic abans d'eliminar-lo: l'element següent de la llista, l'anterior si era l'últim o l'encapçalament de la llista si ha quedat buida. - Contingut que ha de quedar fora d'abast: l'atribut
inert, compatible amb tots els navegadors actuals, fa que un bloc no sigui enfocable ni arribi a les tecnologies de suport. És ideal per a un menú lateral tancat que s'anima fora de la pantalla (ondisplay: noneimpediria la transició) o per a la resta de la pàgina mentre es mostra una capa pròpia. El<dialog>natiu obert ambshowModal()ja torna inert la resta per si mateix.
function alternarMenu(abierto) {
menuLateral.inert = !abierto;
menuLateral.classList.toggle('abierto', abierto);
botonMenu.setAttribute('aria-expanded', String(abierto));
if (abierto) menuLateral.querySelector('a, button')?.focus();
else botonMenu.focus();
}
Per als avisos que no impliquen moure el focus, fes servir regions actives presents des de la càrrega i espera que la persona deixi d'escriure abans d'anunciar els resultats d'una cerca en directe (uns 500 mil·lisegons), per no interrompre cada pulsació.
Prova-ho tu
Obre la consola de les eines de desenvolupament en una aplicació web amb llistes editables i escriu: document.addEventListener('focusin', () => console.log(document.activeElement)). Navega amb el teclat, esborra un element o tanca un panell, i mira la consola. Després escriu document.activeElement: si respon body, el focus s'ha perdut i has trobat un error.
Punt clau
Programa les accions amb click en elements natius, no canviïs de context en enfocar ni en canviar un valor, avisa i deixa allargar qualsevol límit de temps i, cada vegada que el DOM canviï, decideix on queda el focus i com es comunica el canvi.
Resum
- Fes servir
clicken elements natius; executar accions enmousedownopointerdownincompleix 2.5.2 tret que es puguin cancel·lar o que sigui essencial. - Enfocar un element no pot canviar el context (3.2.1) i canviar un valor tampoc sense avís previ (3.2.2): afegeix un botó de confirmació.
- Tota sessió que caduca ha d'avisar abans i permetre allargar-la amb almenys 20 segons i una acció simple (2.2.1); conserva les dades.
- Insereix el contingut després del seu disparador, recol·loca el focus abans d'eliminar elements i fes servir
inertper al que ha de quedar fora d'abast.
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.