La navegación por teclado no es solo cosa de los lectores de pantalla. Decide si un sitio es utilizable para cualquier persona sin ratón, de forma temporal o permanente, y funciona además como prueba de robustez de toda la interfaz. El foco visible y un orden de tabulación coherente forman la base de accesibilidad más rentable que existe, y una de las más olvidadas.
El teclado revela la estructura
En una página bien construida, la tecla Tab desplaza el foco de un elemento interactivo al siguiente, en el orden en que aparecen en el documento. Los elementos nativos (una a con href, button, campos de formulario) son enfocables sin configuración. Un div con un gestor de clic injertado no lo es: permanece invisible para el teclado mientras no se le asigne un rol y una gestión de teclas.
Recorrer un sitio solo con el teclado revela en segundos lo que ninguna captura de pantalla muestra: un menú al que no se llega, un botón fantasma hecho a partir de una imagen clicable, un carrusel que atrapa el foco. El teclado no solo prueba la accesibilidad, prueba la solidez del marcado.
:focus-visible en lugar de eliminar el contorno
El error más extendido cabe en una declaración: outline: none, puesta para borrar el anillo azul que se juzga feo al hacer clic. De paso, priva a quienes usan el teclado de la única señal que les indica dónde están. La solución no es restaurar el contorno antiguo en todas partes, sino reservarlo para el contexto adecuado.
La pseudoclase :focus-visible deja que el navegador decida: muestra el anillo cuando estima que el foco viene del teclado y lo oculta ante un clic de ratón. El contorno aparece así solo donde resulta útil.
/* Ne jamais retirer le contour sans le remplacer. */
:focus-visible {
outline: 3px solid #2d6cdf;
outline-offset: 2px;
border-radius: 2px;
}
/* Souris : pas d'anneau ; clavier : anneau visible. */
:focus:not(:focus-visible) {
outline: none;
}
/* Lien d'evitement : masque, revele au focus clavier. */
.skip-link {
position: absolute;
left: -9999px;
}
.skip-link:focus {
left: 1rem;
top: 1rem;
}
La regla vale para todo componente interactivo, incluidos los elementos personalizados. Un anillo de al menos tres píxeles, con buen contraste sobre el fondo y separado del elemento mediante outline-offset, sigue siendo legible sobre la mayoría de las superficies.
Un sitio que no se puede recorrer de principio a fin con el teclado tiene un defecto funcional, no solo de accesibilidad.
El orden de tabulación sigue al DOM
El orden en que el foco visita los elementos es el del código fuente, no el de la representación. Un bloque movido visualmente con CSS (con order en una cuadrícula, por ejemplo) mantiene su posición original en la tabulación. Cuando el orden visual y el del DOM divergen, la navegación se vuelve desconcertante: conviene corregir la estructura antes que remendarla con el teclado.
Dos herramientas cubren la inmensa mayoría de los casos. El enlace de salto, primer elemento enfocable de la página, permite saltarse la navegación para llegar al contenido. El atributo tabindex="-1" hace que un destino sea enfocable por programa sin insertarlo en el orden de tabulación.
<!-- Premier element focusable de la page -->
<a class="skip-link" href="#contenu">Aller au contenu</a>
<nav>…</nav>
<!-- tabindex="-1" rend la cible focusable par programme,
sans l'ajouter a l'ordre de tabulation. -->
<main id="contenu" tabindex="-1">
<h1>Titre de la page</h1>
</main>
Una regla lo sostiene todo: no usar nunca un tabindex positivo. Fijar tabindex="1", "2" y así sucesivamente fuerza un orden artificial que se desincroniza del contenido a la primera incorporación y se vuelve imposible de mantener. Los únicos valores sanos son 0 (enfocable en el orden natural) y -1 (enfocable solo por programa).
Los componentes a medida, donde se rompe
Menús desplegables, pestañas, cuadros de diálogo: en cuanto un componente se aleja de los elementos nativos, la gestión del teclado se vuelve explícita. Un cuadro de diálogo modal, en particular, debe retener el foco mientras está abierto; de lo contrario, la tabulación se marcha a la página que queda detrás, fuera de la vista.
// Piege de focus minimal pour une boite de dialogue.
function piegerFocus(dialogue) {
const focusables = dialogue.querySelectorAll(
'a[href], button:not([disabled]), input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const premier = focusables[0];
const dernier = focusables[focusables.length - 1];
dialogue.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
if (e.shiftKey && document.activeElement === premier) {
e.preventDefault();
dernier.focus();
} else if (!e.shiftKey && document.activeElement === dernier) {
e.preventDefault();
premier.focus();
}
});
}
El atrapamiento del foco es solo la mitad del contrato. Al abrir, el foco debe ir al cuadro o a su primer campo; al cerrar, debe volver al elemento que lo activó; la tecla Escape debe cerrarlo. Sin este ciclo completo, el modal sigue siendo una trampa para quien usa el teclado.
Formularios: etiquetas asociadas y foco en el error
Los formularios concentran la mayoría de las interacciones por teclado, y buena parte de los defectos. Cada campo debe vincularse a una label explícita, mediante el atributo for que apunta al id del campo: al hacer clic en la etiqueta, el campo recibe el foco y las tecnologías de asistencia anuncian el nombre correcto. Un placeholder no sustituye a una etiqueta, ya que desaparece en cuanto se escribe.
Al validar, el foco debe ir al primer campo con error, y el mensaje correspondiente vincularse al campo con aria-describedby. Así se conduce a quien usa el teclado directamente al problema, sin volver a tabular todo el formulario para localizarlo.
Qué selector para qué necesidad
| Selector | Se activa cuando | Uso típico |
|---|---|---|
:focus | el elemento recibe el foco, ratón o teclado | demasiado amplio por sí solo, evitar para el anillo |
:focus-visible | el navegador estima que el foco es «de teclado» | el anillo de foco, el caso por defecto |
:focus-within | un descendiente tiene el foco | resaltar un campo o un menú padre |
El punto de vigilancia. outline: none sin un reemplazo visible es el defecto de accesibilidad más común y uno de los más fáciles de corregir. El criterio 2.4.7 de las WCAG exige un indicador de foco visible; la versión 2.2 añade requisitos de contraste y de superficie mínima para ese indicador. Una comprobación rápida: desconectar el ratón y recorrer toda la página con el teclado.
Lo que hay que recordar
- La navegación por teclado es una prueba de robustez de toda la interfaz, no una opción para una minoría.
:focus-visiblereserva el anillo de foco para el teclado sin suprimirlo para todos.- El orden de tabulación sigue al DOM; un enlace de salto y
tabindexlimitado a0y-1bastan. - Los componentes a medida exigen una gestión explícita del foco, sobre todo los cuadros de diálogo modales.
En mis auditorías, la primera prueba que hago es siempre la misma: aparto el ratón y tabulo. En menos de un minuto sale a la luz la mitad de los defectos de accesibilidad de un sitio, y rara vez son los más caros de corregir. Restablecer un foco visible y enderezar el orden de tabulación suele resolverse con unas pocas líneas de CSS y un enlace de salto. Es la mejor relación esfuerzo / resultado que conozco en este terreno. — Simon Janvier
Para profundizar
Referencia: :focus-visible en MDN Web Docs, y el criterio WCAG 2.4.7 «Foco visible».
