Accesibilidad web (a11y) en HTML
En esta lección
La accesibilidad web consiste en hacer páginas que pueda usar todo el mundo, también las personas con discapacidad visual, auditiva, motora o cognitiva. Se abrevia a11y: una “a”, once letras y una “y”. En esta lección verás por qué importa, qué dicen las normas y, sobre todo, qué puedes hacer desde el HTML, que es donde se decide la mayor parte de la accesibilidad de una web.
La buena noticia: si escribes HTML correcto y semántico, ya tienes hecho más de la mitad del trabajo.
Por qué importa
- Por las personas. Mucha gente navega de formas distintas a la tuya: con un lector de pantalla que lee la página en voz alta, solo con el teclado, con la pantalla ampliada al 400 %, con subtítulos o con control por voz. Y cualquiera puede tener una limitación temporal: un brazo escayolado, el sol dando en la pantalla del móvil, un sitio ruidoso sin auriculares.
- Por la ley. Desde el 28 de junio de 2025 se aplica la Ley Europea de Accesibilidad (EAA, Directiva 2019/882; en España, la Ley 11/2023). Obliga a que muchos servicios digitales para el público sean accesibles: tiendas online, banca, transporte, libros electrónicos… Las administraciones públicas ya tenían esa obligación desde antes.
- Por el SEO y la calidad. Los buscadores leen tu página de forma parecida a un lector de pantalla: encabezados, textos alternativos y enlaces descriptivos les ayudan a entenderla. Además, una web accesible suele ser más clara para todo el mundo.
Las pautas WCAG 2.2
Las WCAG (Web Content Accessibility Guidelines) son las pautas internacionales de accesibilidad. La versión actual es la 2.2, y la normativa europea se basa en ellas. Se organizan en cuatro principios: el contenido debe ser perceptible, operable, comprensible y robusto.
Cada criterio tiene un nivel:
| Nivel | Qué significa |
|---|---|
| A | Lo mínimo. Sin esto, algunas personas no pueden usar la web |
| AA | El nivel que exigen las leyes. Es el objetivo razonable |
| AAA | El más exigente. Se aplica en partes concretas, no a toda una web |
Por ejemplo, para el contraste del texto normal, AA pide una relación de 4,5:1 y AAA, de 7:1. WCAG 2.2 añadió criterios como que el elemento enfocado no quede tapado por una cabecera fija, o que los botones táctiles midan al menos 24 x 24 píxeles.
HTML semántico primero
Cada elemento HTML lleva un rol implícito que las tecnologías de apoyo entienden. Un <button> se anuncia como “botón”, se enfoca con Tab y se activa con Intro o espacio. Un <div> no hace nada de eso.
<!-- Mal: parece un botón, pero no lo es -->
<div class="boton" onclick="reservar()">Reservar</div>
<!-- Bien: gratis tienes foco, teclado y anuncio correcto -->
<button type="button" onclick="reservar()">Reservar</button>
Regla de oro: usa el elemento que corresponde. <a> para ir a otro sitio, <button> para hacer una acción, <nav> para la navegación, <ul> para listas, <table> para datos tabulares. Tienes todos los detalles en HTML semántico.
Landmarks o regiones
Los elementos <header>, <nav>, <main>, <aside> y <footer> crean regiones (landmarks). Un usuario de lector de pantalla puede ver la lista de regiones y saltar directamente al contenido principal. Si hay dos <nav>, distínguelas con un nombre:
<nav aria-label="Principal">...</nav>
<nav aria-label="Pie de página">...</nav>
Jerarquía de encabezados
Los encabezados son el índice de la página. Muchos usuarios de lectores de pantalla navegan saltando de uno a otro.
- Un solo
<h1>con el tema de la página. - No te saltes niveles: después de un
<h2>viene un<h3>, no un<h4>. - No elijas el nivel por el tamaño de letra; eso se cambia con CSS.
El idioma de la página
<html lang="es">
Con lang, el lector de pantalla usa la pronunciación correcta. Si una frase está en otro idioma, márcala: <span lang="en">Sold out</span>. Lo viste en atributos globales.
Imágenes y textos alternativos
Toda imagen necesita alt. El texto debe sustituir a la imagen, no describirla con todo detalle:
<img src="grafico-socios.png" alt="El número de socios pasó de 120 en 2024 a 210 en 2026">
<img src="adorno-montanias.svg" alt="">
Una imagen decorativa lleva alt="" (vacío, no ausente) para que el lector la ignore. Si la imagen es un enlace, el alt dice a dónde lleva. Tienes más ejemplos en imágenes en HTML.
Formularios accesibles
- Cada campo con su
<label>. Elplaceholderno sustituye a la etiqueta: desaparece al escribir y suele tener poco contraste. - Agrupa opciones relacionadas (botones de opción) con
<fieldset>y<legend>. - Explica los requisitos antes de que la persona se equivoque, y enlaza la ayuda con
aria-describedby. - Los errores, en texto, no solo con un borde rojo.
<label for="telefono">Teléfono</label>
<input type="tel" id="telefono" autocomplete="tel" aria-describedby="ayuda-tel">
<p id="ayuda-tel">Solo lo usaremos si cambia el horario de tu clase.</p>
Repasa los fundamentos en formularios en HTML.
Contraste y color
El texto debe destacar lo suficiente sobre el fondo. Con nivel AA:
- Texto normal: contraste mínimo de 4,5:1.
- Texto grande (desde 24 px, o desde unos 18,7 px en negrita): 3:1.
- Iconos, bordes de campos y otros elementos gráficos necesarios: 3:1.
Un gris claro sobre blanco queda elegante, pero mucha gente no lo lee. Comprueba los colores con el inspector del navegador, que muestra el contraste al seleccionar un texto.
Y nunca uses solo el color para transmitir información. “Los campos en rojo son obligatorios” no sirve a quien no distingue el rojo. Añade un texto o un símbolo.
Teclado y foco
Todo lo que se puede hacer con el ratón debe poder hacerse con el teclado. Pruébalo: Tab avanza, Mayús + Tab retrocede, Intro activa enlaces y botones, espacio marca casillas y pulsa botones, las flechas mueven entre opciones.
- No quites el indicador de foco.
outline: nonesin alternativa deja a la persona sin saber dónde está. Mejor dale estilo:
:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
- Respeta el orden del código. El foco sigue el orden del HTML. Si reordenas con CSS, el recorrido con Tab se vuelve caótico.
- Evita
tabindexmayor que 0. Rompe el orden natural. Usa0para hacer enfocable algo que no lo es (mejor aún: usa el elemento correcto) y-1para enfocar solo desde JavaScript.
Enlace para saltar al contenido
Quien navega con teclado tendría que pasar por todo el menú en cada página. Un enlace de salto al principio lo evita:
<a class="saltar" href="#contenido">Saltar al contenido</a>
...
<main id="contenido">...</main>
Con CSS se oculta fuera de la pantalla y aparece solo al recibir el foco (mira el ejemplo de esta lección).
Enlaces descriptivos
Los lectores de pantalla permiten ver una lista con todos los enlaces de la página. Si diez dicen “Leer más”, esa lista no sirve.
<!-- Mal -->
<a href="cursos/iniciacion.html">Leer más</a>
<!-- Bien -->
<a href="cursos/iniciacion.html">Más sobre el curso de iniciación</a>
Lo verás con más detalle en enlaces en HTML.
ARIA básico
ARIA (Accessible Rich Internet Applications) es un conjunto de atributos que añaden información para las tecnologías de apoyo. No cambian nada visualmente ni añaden comportamiento: solo cambian lo que se anuncia.
La primera regla de ARIA
Si puedes usar un elemento HTML nativo con el significado y el comportamiento que necesitas, úsalo en lugar de añadir ARIA.
Un <div role="button"> se anuncia como botón, pero no se enfoca con Tab ni se activa con Intro: eso tendrías que programarlo tú. Un <button> ya lo trae todo. Se dice a menudo que “nada de ARIA es mejor que un ARIA mal puesto”.
Los atributos más útiles
| Atributo | Para qué sirve | Ejemplo |
|---|---|---|
aria-label | Da un nombre cuando no hay texto visible | <button aria-label="Cerrar">×</button> |
aria-labelledby | Toma el nombre de otro elemento por su id | <section aria-labelledby="t-precios"> |
aria-describedby | Añade una descripción extra (ayudas, errores) | <input aria-describedby="ayuda-tel"> |
aria-live | Anuncia cambios de contenido sin mover el foco | <p aria-live="polite"> |
aria-expanded | Indica si algo desplegable está abierto | <button aria-expanded="false"> |
aria-current | Marca el elemento actual de un conjunto | <a aria-current="page"> |
aria-hidden | Oculta algo a las tecnologías de apoyo | <svg aria-hidden="true"> |
role | Cambia el rol de un elemento | <div role="alert"> |
Un menú desplegable
Aquí ARIA sí tiene sentido, porque HTML no tiene un atributo para “este botón abre y cierra aquello”:
<button type="button" aria-expanded="false" aria-controls="menu">Menú</button>
<ul id="menu" hidden>...</ul>
Cuando JavaScript abre el menú, cambia aria-expanded a "true". Así el lector anuncia “Menú, botón, expandido”.
Mensajes que aparecen: aria-live
Si tras enviar un formulario escribes “Reserva confirmada” en un párrafo, quien no ve la pantalla no se entera. Con aria-live="polite", el lector lo anuncia cuando termina lo que estaba leyendo. Usa role="alert" (equivale a aria-live="assertive") solo para errores urgentes, porque interrumpe.
Cuidado: la región
aria-livedebe existir en la página antes de cambiar su texto. Si la creas y la rellenas a la vez, muchos lectores no la anuncian.
Recuerda también que <details>, <dialog> y popover ya gestionan estos estados por ti: lo viste en elementos interactivos.
Cómo probar la accesibilidad
- Solo teclado. Desconecta el ratón y recorre la página. ¿Ves siempre dónde está el foco? ¿Llegas a todo? ¿Puedes salir de los menús?
- Lector de pantalla. NVDA en Windows (gratis), VoiceOver en Mac e iPhone (Cmd + F5), TalkBack en Android. Escucha cómo se anuncian tus botones y formularios.
- Zoom al 200 %. Nada debe cortarse ni solaparse.
- Lighthouse. En las herramientas de desarrollo de Chrome, pestaña Lighthouse, categoría Accessibility.
- WAVE. Una extensión que marca sobre la página los errores: imágenes sin
alt, campos sin etiqueta, poco contraste…
Consejo: las herramientas automáticas solo detectan una parte de los problemas. Un 100 en Lighthouse no garantiza una web accesible; la prueba con teclado y lector de pantalla sigue siendo imprescindible.
Errores frecuentes
- Botones y enlaces hechos con
<div>o<span>. - Imágenes sin
alto conalt="imagen". - Campos con
placeholderpero sin<label>. outline: nonesin sustituto visible.- Saltarse niveles de encabezado o elegirlos por tamaño.
- Añadir
roleyaria-*a elementos que ya tienen ese significado (<button role="button">). - Transmitir información solo con color.
- Olvidar
langen el<html>.
Resumen
| Qué | Cómo |
|---|---|
| Estructura | Elementos semánticos y landmarks |
| Encabezados | Un <h1>, niveles sin saltos |
| Imágenes | alt que sustituya a la imagen; alt="" si es decorativa |
| Formularios | <label> en cada campo, ayudas con aria-describedby |
| Contraste | 4,5:1 texto normal; 3:1 texto grande y gráficos (AA) |
| Teclado | Todo accesible con Tab, foco visible, enlace de salto |
| Enlaces | Texto que diga a dónde llevan |
| ARIA | Solo cuando HTML no basta; primero, lo nativo |
| Idioma | lang="es" en <html> |
| Normas | WCAG 2.2 nivel AA, exigido por la ley europea desde 2025 |
| Pruebas | Teclado, lector de pantalla, Lighthouse y WAVE |
Pruébalo tú
Cambia el código y pulsa Ejecutar (o Ctrl + Enter).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.