Saltar al contenido
accesibilidad.html · devschool

Accesibilidad web (a11y) en HTML

Lección 20 de 23 · 10 min de lectura · Actualizado el

En esta lección
  1. Por qué importa
  2. Las pautas WCAG 2.2
  3. HTML semántico primero
  4. Imágenes y textos alternativos
  5. Formularios accesibles
  6. Contraste y color
  7. Teclado y foco
  8. Enlaces descriptivos
  9. ARIA básico
  10. Cómo probar la accesibilidad
  11. Errores frecuentes
  12. Resumen

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:

NivelQué significa
ALo mínimo. Sin esto, algunas personas no pueden usar la web
AAEl nivel que exigen las leyes. Es el objetivo razonable
AAAEl 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>. El placeholder no 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: none sin 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 tabindex mayor que 0. Rompe el orden natural. Usa 0 para hacer enfocable algo que no lo es (mejor aún: usa el elemento correcto) y -1 para 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

AtributoPara qué sirveEjemplo
aria-labelDa un nombre cuando no hay texto visible<button aria-label="Cerrar">×</button>
aria-labelledbyToma el nombre de otro elemento por su id<section aria-labelledby="t-precios">
aria-describedbyAñade una descripción extra (ayudas, errores)<input aria-describedby="ayuda-tel">
aria-liveAnuncia cambios de contenido sin mover el foco<p aria-live="polite">
aria-expandedIndica si algo desplegable está abierto<button aria-expanded="false">
aria-currentMarca el elemento actual de un conjunto<a aria-current="page">
aria-hiddenOculta algo a las tecnologías de apoyo<svg aria-hidden="true">
roleCambia 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-live debe 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

  1. 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?
  2. 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.
  3. Zoom al 200 %. Nada debe cortarse ni solaparse.
  4. Lighthouse. En las herramientas de desarrollo de Chrome, pestaña Lighthouse, categoría Accessibility.
  5. 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 alt o con alt="imagen".
  • Campos con placeholder pero sin <label>.
  • outline: none sin sustituto visible.
  • Saltarse niveles de encabezado o elegirlos por tamaño.
  • Añadir role y aria-* a elementos que ya tienen ese significado (<button role="button">).
  • Transmitir información solo con color.
  • Olvidar lang en el <html>.

Resumen

QuéCómo
EstructuraElementos semánticos y landmarks
EncabezadosUn <h1>, niveles sin saltos
Imágenesalt que sustituya a la imagen; alt="" si es decorativa
Formularios<label> en cada campo, ayudas con aria-describedby
Contraste4,5:1 texto normal; 3:1 texto grande y gráficos (AA)
TecladoTodo accesible con Tab, foco visible, enlace de salto
EnlacesTexto que diga a dónde llevan
ARIASolo cuando HTML no basta; primero, lo nativo
Idiomalang="es" en <html>
NormasWCAG 2.2 nivel AA, exigido por la ley europea desde 2025
PruebasTeclado, lector de pantalla, Lighthouse y WAVE

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

accesibilidad.html
Resultado

Pon a prueba lo que has aprendido

[HTML] ¿Qué dice la primera regla de ARIA?

[HTML] ¿Qué problema de accesibilidad tiene este código?
<div class="boton" onclick="reservar()">Reservar</div>

[HTML] Tras enviar un formulario, JavaScript escribe "Reserva confirmada" en un párrafo. ¿Cómo haces que un lector de pantalla lo anuncie?

[HTML] Según WCAG 2.2 nivel AA, ¿qué contraste mínimo necesita el texto de tamaño normal respecto a su fondo?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.