Accesibilidad Web (a11y): Guía Práctica para Desarrolladores
Aprende los principios esenciales de accesibilidad, atributos ARIA, patrones de navegación por teclado y herramientas de prueba para que tus aplicaciones web sean utilizables por todos.
Más de 1.300 millones de personas — el 16% de la población mundial — viven con algún tipo de discapacidad. La accesibilidad web garantiza que tu sitio funcione para usuarios que dependen de lectores de pantalla, navegación por teclado, acceso por interruptor u otras tecnologías de asistencia. Más allá de la inclusión, los sitios accesibles tienen mejor posicionamiento en buscadores, funcionan mejor en dispositivos móviles y, con frecuencia, son un requisito legal.
Los cuatro principios POUR
Las Pautas de Accesibilidad para el Contenido Web (WCAG) se basan en cuatro principios fundamentales. El contenido debe ser:
- Perceptible — La información debe presentarse de formas que los usuarios puedan percibir (no solo de forma visual).
- Operable — Toda la funcionalidad debe estar disponible desde el teclado.
- Comprensible — El contenido y las interfaces deben ser comprensibles.
- Robusto — El contenido debe poder ser interpretado por tecnologías de asistencia.
WCAG 2.2 define tres niveles de conformidad:
- A — Mínimo (imprescindible)
- AA — Objetivo estándar para la mayoría de las organizaciones
- AAA — Máximo (aspiracional para algunos contenidos)
La mayoría de los requisitos legales (ADA, EN 301 549, EAA) exigen conformidad AA.
Primero, HTML semántico
Lo más impactante que puedes hacer por la accesibilidad es usar el elemento HTML correcto para cada propósito. Los navegadores y los lectores de pantalla ya saben qué hacer con los elementos semánticos:
<!-- ❌ Sopa de divs — sin semántica -->
<div class="header">
<div class="nav">
<div class="nav-item" onclick="navigate()">Home</div>
</div>
</div>
<!-- ✅ HTML semántico — los lectores de pantalla lo entienden -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
Elementos semánticos clave y sus roles:
| Elemento | Rol |
|---|---|
<header>, <footer> |
Regiones de referencia |
<nav> |
Referencia de navegación |
<main> |
Contenido principal (uno por página) |
<aside> |
Contenido complementario |
<h1>–<h6> |
Jerarquía de encabezados |
<button> |
Control interactivo |
<a href> |
Enlace de navegación |
<label> |
Etiqueta de campo de formulario |
<table> |
Datos tabulares |
Imágenes y texto alternativo
Toda imagen significativa necesita un atributo alt que describa su contenido. Las imágenes decorativas llevan un alt="" vacío para que los lectores de pantalla las omitan:
<!-- Imagen significativa -->
<img src="chart.png" alt="Gráfico de barras que muestra un aumento del 40% en ingresos en el Q1 de 2026">
<!-- Imagen decorativa -->
<img src="divider.svg" alt="">
<!-- Botón con icono — describe la acción, no el icono -->
<button>
<img src="trash.svg" alt="Eliminar elemento">
</button>
<!-- Evita: "imagen de" es redundante -->
<!-- ❌ --> <img src="cat.jpg" alt="Imagen de un gato">
<!-- ✅ --> <img src="cat.jpg" alt="Gato atigrado naranja sentado en un alféizar">
Contraste de color
Los usuarios con baja visión o daltonismo dependen de un contraste suficiente entre el texto y el fondo.
Requisitos WCAG AA:
- Texto normal (< 18pt): relación de contraste mínima de 4.5:1
- Texto grande (≥ 18pt o 14pt en negrita): relación de contraste mínima de 3:1
- Componentes de interfaz y objetos gráficos: mínimo 3:1
No dependas únicamente del color para transmitir información:
<!-- ❌ Indicador de estado solo por color -->
<span class="text-red-500">Error</span>
<!-- ✅ Color + icono + texto -->
<span class="text-red-500 flex items-center gap-1">
<svg aria-hidden="true"><!-- icono de error --></svg>
Error: Dirección de correo electrónico no válida
</span>
Formularios: etiquetas, errores y descripciones
Todo control de formulario necesita una etiqueta visible y asociada:
<!-- ✅ Asociación explícita de etiqueta -->
<label for="email">Dirección de correo electrónico</label>
<input id="email" type="email" aria-describedby="email-hint email-error">
<p id="email-hint" class="text-sm text-gray-500">Nunca compartiremos tu correo.</p>
<p id="email-error" role="alert" class="text-sm text-red-600" hidden>
Por favor, introduce una dirección de correo válida.
</p>
Patrones clave de accesibilidad en formularios:
- Usa
for/idpara asociar etiquetas con campos - Usa
aria-describedbypara texto de ayuda y mensajes de error - Usa
role="alert"oaria-live="polite"para mensajes de error dinámicos - Usa
aria-required="true"o el atributo nativorequired - Agrupa campos relacionados con
<fieldset>y<legend>
Navegación por teclado
Todos los elementos interactivos deben ser accesibles y operables con el teclado:
- Tab — avanzar por los elementos enfocables
- Shift+Tab — retroceder
- Enter/Espacio — activar botones y casillas de verificación
- Teclas de flecha — navegar dentro de componentes (menús, pestañas, controles deslizantes)
- Escape — cerrar modales, descartar menús desplegables
Los indicadores de foco deben ser visibles. Nunca hagas esto sin una alternativa:
/* ❌ Oculta completamente el indicador de foco */
*:focus { outline: none; }
/* ✅ Estilo de foco personalizado que sigue siendo visible */
*:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
ARIA: cuándo y cómo usarlo
Los atributos ARIA (Accessible Rich Internet Applications) añaden significado semántico cuando el HTML por sí solo no es suficiente. La primera regla de ARIA: no uses ARIA si el HTML nativo puede hacer el trabajo.
<!-- Etiquetar elementos sin etiquetas visibles -->
<button aria-label="Cerrar diálogo">✕</button>
<!-- Describir el estado expandido -->
<button aria-expanded="false" aria-controls="menu">Menú</button>
<ul id="menu" hidden>...</ul>
<!-- Región en vivo para contenido dinámico -->
<div aria-live="polite" aria-atomic="true">
<!-- Los lectores de pantalla anuncian los cambios en esta área -->
3 resultados encontrados
</div>
<!-- Rol de referencia cuando no hay elemento semántico disponible -->
<div role="search">
<input type="search" placeholder="Buscar...">
</div>
Gestión del foco en SPAs y modales
En las aplicaciones de página única, la navegación entre páginas no provoca un restablecimiento del foco del navegador. Cuando se carga una "página", mueve el foco a una ubicación significativa:
// Tras la navegación, enfoca el encabezado principal
document.querySelector("h1")?.focus();
Para modales:
- Cuando el modal se abre, mueve el foco al primer elemento enfocable dentro de él
- Atrapa el foco dentro del modal mientras está abierto (evita que Tab alcance el contenido detrás)
- Cuando el modal se cierra, devuelve el foco al elemento que lo activó
Pruebas de accesibilidad
Herramientas automatizadas (detectan ~30-40% de los problemas)
- Extensión de navegador axe DevTools
- Auditoría de accesibilidad Lighthouse en Chrome DevTools
- Extensión de navegador WAVE
Pruebas manuales (necesarias para una cobertura completa)
- Navegación solo con teclado — desconecta el ratón y navega por todo tu sitio
- Pruebas con lector de pantalla — NVDA + Firefox (Windows), VoiceOver + Safari (Mac/iOS)
- Zoom al 200% — asegúrate de que no se pierde ni se superpone ningún contenido
- Simulación de daltonismo — Chrome DevTools → Rendering → Emulate vision deficiencies
Legibilidad
El lenguaje claro mejora la accesibilidad para usuarios con discapacidades cognitivas. Usa nuestra herramienta Readability Score para comprobar el nivel de lectura de tu contenido — apunta a un nivel de grado 8-10 para el público general.
Mejoras rápidas que puedes aplicar hoy
- Añade texto
alta todas las imágenes - Asegúrate de que todos los campos de formulario tienen elementos
<label>asociados - Comprueba que el contraste de color cumple el ratio 4.5:1 para el texto del cuerpo
- Añade estilos
:focus-visibley nunca elimines los contornos sin un reemplazo - Usa
<button>para acciones y<a href>para navegación (nunca al revés) - Añade
lang="es"(o el idioma correspondiente) a tu elemento<html> - Usa un solo
<h1>por página y mantén una jerarquía de encabezados lógica
La accesibilidad no es un complemento — es una característica de calidad. Crear productos accesibles desde el principio es mucho más económico que adaptarlos después, y hace que tus productos sean mejores para todos.