Lliçó 3 de 10 · 14 min de lectura · Revisada el 26/10/2026
Com funciona el focus: enfocable, tabulable, esdeveniments i contingut ocult
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.
A la lliçó anterior vam veure que tot ha de ser assolible, activable i completable amb teclat. Per aconseguir-ho, i per diagnosticar per què alguna cosa falla, cal entendre què és exactament el focus i com el gestiona el navegador. Aquesta lliçó explica el model de focus del navegador, com observar-lo des de JavaScript i CSS, el criteri 3.2.1 En rebre el focus i el problema del «focus fantasma» en el contingut ocult.
Enfocable no és el mateix que tabulable
El focus és l'estat de l'únic element del document que rep en aquell moment les pulsacions de teclat. Com a màxim hi ha un element amb focus per document; si no en té cap, document.activeElement retorna el <body>. L'especificació HTML distingeix dos nivells:
- Enfocable: l'element pot rebre el focus d'alguna manera, ja sigui amb Tab, amb un clic o per programa amb
elemento.focus(). - Tabulable (a l'especificació, «enfocable seqüencialment»): a més, forma part de la seqüència que recorren Tab i Maj+Tab.
| Element | Enfocable? | Tabulable? |
|---|---|---|
a amb href | Sí | Sí |
a sense href | No | No |
button, input, select, textarea habilitats | Sí | Sí |
Els mateixos amb l'atribut disabled | No | No |
summary d'un details | Sí | Sí |
Element amb contenteditable | Sí | Sí |
iframe | Sí: el focus entra al seu document | Sí |
div, span, p, encapçalaments | No | No |
Qualsevol element amb tabindex="0" | Sí | Sí |
Qualsevol element amb tabindex="-1" | Sí | No |
disabled davant aria-disabled
L'atribut disabled treu el control de la seqüència de tabulació. Té un cost: qui tabula per un formulari no sap que existeix el botó «Envia la sol·licitud» fins que s'habilita, i no hi pot arribar per sentir per què està desactivat. L'alternativa és aria-disabled="true", que comunica l'estat a les tecnologies de suport però manté l'element enfocable. A canvi, el bloqueig de l'acció l'ha de fer el teu codi:
<button type="submit" aria-disabled="true" aria-describedby="aviso-envio">Envia la sol·licitud</button>
<p id="aviso-envio">Completa els camps obligatoris per poder enviar.</p>
boton.addEventListener('click', (e) => {
if (boton.getAttribute('aria-disabled') === 'true') {
e.preventDefault(); // no s'envia, però el botó continua localitzable
return;
}
enviar();
});
Contenidors amb desplaçament
Una caixa amb overflow: auto (una taula ampla, unes condicions legals llargues) només es pot desplaçar amb les fletxes si alguna cosa de dins té el focus. Si el seu contingut no inclou cap element enfocable, la persona que fa servir teclat no pot llegir el que queda ocult, i això incompleix el 2.1.1. Firefox i les versions recents de Chrome i Edge fan enfocables aquests contenidors automàticament, però no tots els navegadors ho fan. Per no dependre'n, fes-ho explícit i dona-li un nom perquè el lector de pantalla anunciï què és:
<div class="tabla-ancha" tabindex="0" role="region" aria-label="Tarifes 2026, taula amb desplaçament horitzontal">
<table>…</table>
</div>
Observar el focus des de JavaScript i CSS
Gestionar el focus exigeix saber-lo llegir. Aquestes són les peces que faràs servir contínuament:
document.activeElementretorna l'element que té el focus.- Els esdeveniments
focusiblures disparen a l'element que guanya o perd el focus i no fan bombolla. Els seus equivalentsfocusinifocusoutsí que en fan, així que els pots escoltar en un contenidor; la seva propietatrelatedTargetindica on va (o d'on ve) el focus. elemento.focus()mou el focus i desplaça la vista fins a l'element. Ambfocus({ preventScroll: true })no es desplaça; fes-lo servir amb cura, perquè l'element enfocat ha de quedar a la vista.- En CSS,
:focuss'aplica a qualsevol element amb focus;:focus-visible, només quan el navegador considera que convé mostrar l'indicador (en navegar amb teclat i, als camps de text, gairebé sempre);:focus-within, a l'element que té el focus o que conté el que el té, útil per ressaltar una targeta o mantenir obert un submenú.
Exemple
Tancar un desplegable quan el focus en surt, sense tancar-lo mentre la persona es mou per les seves opcions:
desplegable.addEventListener('focusout', (e) => {
// relatedTarget és l'element que rep el focus (o null)
if (!desplegable.contains(e.relatedTarget)) {
cerrarDesplegable();
}
});3.2.1 En rebre el focus: enfocar no és decidir
Aquest criteri de nivell A exigeix que, quan un component rep el focus, no s'iniciï cap canvi de context: obrir una finestra nova, moure el focus a un altre component, enviar un formulari o canviar de manera substancial el contingut de la pàgina. Qui navega amb teclat o amb lector de pantalla recorre els elements per explorar-los; si el simple fet de passar per un dispara una acció, la persona perd el control.
Errors típics: avançar al pas següent d'un formulari quan el focus arriba a l'últim camp, obrir una finestra emergent en enfocar un enllaç, o llançar una cerca en entrar al cercador. El que sí que es permet és mostrar informació addicional, com un tooltip (una etiqueta emergent) o un ressaltat, perquè no canvia el context; aquest contingut ha de complir l'1.4.13 Contingut en passar el cursor o en rebre el focus, que veuràs al curs de components interactius.
Error freqüent
<a href="/tramites" onfocus="this.blur()">Tràmits</a>Es feia servir perquè l'indicador de focus no aparegués mai. En treure el focus tan bon punt arriba, l'enllaç esdevé inassolible i el focus salta a un lloc imprevisible. El W3C ho documenta com l'error F55, que incompleix alhora el 2.1.1 Teclat, el 2.4.7 Focus visible i el 3.2.1 En rebre el focus. Si molesta l'indicador en fer clic, la solució és :focus-visible, no treure el focus.
Contingut ocult i el «focus fantasma»
Si un element no es veu però continua sent tabulable, la persona prem Tab i l'indicador desapareix: el focus és en un enllaç del menú mòbil plegat fora de la pantalla, a la quarta diapositiva d'un carrusel o dins d'un acordió tancat amb height: 0. En diem focus fantasma. Incompleix el 2.4.7 Focus visible i, sovint, el 2.4.3 Ordre del focus, perquè el recorregut passa per elements que no hi són. El curs de CSS tracta l'ocultació en general; aquí el que importa és què fa cada tècnica amb el focus.
Infografia · Conceptes clau
Amagar contingut: què passa amb el focus
Sis maneres habituals d'amagar alguna cosa i si els seus elements continuen a la seqüència de Tab
- display:none i hiddenNi es veu, ni rep el focus, ni arriba al lector de pantalla
- visibility:hiddenNo és enfocable i es pot animar: útil en menús que llisquen
- inertVisible, però ni enfocable ni perceptible: el fons d'una finestra modal
- aria-hidden="true"Surt del lector però continua enfocable: mai amb enllaços a dins
- Fora de pantallaAmb transform o posició negativa continua a la seqüència de Tab
- opacity:0 o height:0Invisible però tabulable: és l'origen del focus fantasma
Llegeix la infografia com a text
Sis targetes sobre tècniques d'ocultació i el seu efecte en el focus. Primera: display:none i l'atribut hidden; el contingut no es veu, no rep el focus i no arriba al lector de pantalla. Segona: visibility:hidden; tampoc no és enfocable i es pot animar, útil per a menús que llisquen. Tercera: inert; el contingut continua visible, però no és enfocable ni perceptible, adequat per al fons d'una finestra modal. Quarta: aria-hidden="true"; el treu del lector però continua sent enfocable, així que no ha d'envoltar mai enllaços ni botons. Cinquena: contingut fora de pantalla amb transform o posició negativa; continua a la seqüència de Tab. Sisena: opacity:0 o height:0; és invisible però tabulable i provoca el focus fantasma. Les tres primeres treuen el contingut del focus; les tres últimes, no.
De les tècniques habituals, quatre treuen el contingut de la seqüència de tabulació: display: none, l'atribut hidden, visibility: hidden (que, a més, es pot animar) i inert (que deixa el contingut visible, però no enfocable ni perceptible). Les altres (posicionar-lo fora de pantalla, transform, opacity: 0, height: 0, clip-path) l'amaguen a la vista però el deixen tabulable. I aria-hidden="true" fa el contrari: el treu del lector de pantalla però no del focus, així que no ha d'envoltar mai enllaços ni botons.
Exemple
Incorrecte: un menú lateral que s'amaga només desplaçant-lo. Els seus 15 enllaços continuen a la seqüència de Tab encara que el menú estigui tancat.
.menu-lateral { transform: translateX(-100%); transition: transform .3s; }
.menu-lateral.abierto { transform: none; }Correcte: s'afegeix visibility, que també es pot animar, i els enllaços surten de la seqüència mentre el menú està tancat.
.menu-lateral {
transform: translateX(-100%);
visibility: hidden;
transition: transform .3s, visibility .3s;
}
.menu-lateral.abierto { transform: none; visibility: visible; }Fronteres del focus: iframes i shadow DOM
En tabular, el focus entra al document d'un iframe, el recorre i en surt pel final. Si el contingut incrustat (un reproductor, un mapa, un xat de tercers) atrapa el focus o no mostra indicador, el problema és de la teva pàgina encara que no hagis escrit aquest codi, perquè la conformitat s'avalua sobre la pàgina completa. Prova amb teclat qualsevol component de tercers abans d'incrustar-lo.
Els elements enfocables d'un component web amb shadow DOM (un subarbre encapsulat dins d'un element amfitrió) es recorren en la posició de l'amfitrió. Dos detalls que confonen en depurar: document.activeElement retorna l'amfitrió, no l'element intern (per a això hi ha anfitrion.shadowRoot.activeElement), i si crees l'arrel amb attachShadow({ mode: 'open', delegatesFocus: true }), en enfocar l'amfitrió el focus passa automàticament al seu primer element enfocable.
Prova-ho tu
Obre a Chrome o Edge un web que facis servir sovint. Obre les eines per a desenvolupadors (F12), ves a la pestanya Consola i prem la icona de l'ull («Crea una expressió en directe»). Escriu document.activeElement. Ara tabula per la pàgina: l'expressió mostrarà en cada moment quin element té el focus. Busca una parada en què no vegis res a la pantalla: hauràs trobat un focus fantasma o un indicador eliminat.
Punt clau
Abans de corregir un problema de teclat, esbrina on és realment el focus. El que s'amaga ha de sortir de la seqüència de tabulació (hidden, display: none, visibility: hidden o inert), mai només de la vista o només del lector, i rebre el focus no ha de disparar mai un canvi de context.
Resum
- Enfocable vol dir que pot rebre el focus; tabulable, que a més és a la seqüència de Tab.
disabledtreu el control de la seqüència;aria-disabledl'hi manté. - Fes enfocables (amb nom) els contenidors amb desplaçament que no tenen res d'enfocable a dins.
- Fes servir
focusinifocusoutambrelatedTargetper saber quan el focus entra en un component o en surt. - 3.2.1: rebre el focus no pot obrir finestres, enviar formularis ni moure el focus a un altre lloc.
- El contingut ocult també ha de sortir de la seqüència de tabulació;
aria-hiddensobre elements enfocables és un error, i el contingut d'iframei de shadow DOM també forma part de la teva pàgina.
Portes 5 lliçons d'aquest curs: que no es perdin
Crea el teu compte gratis i desa el que ja has llegit 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.