Por qué la accesibilidad web importa
La accesibilidad web (a11y) no es un extra ni un "nice to have". Es un requisito fundamental que beneficia a todos tus usuarios:
- 1 de cada 5 personas tiene alguna forma de discapacidad
- Usuarios con discapacidades temporales (brazo roto, infeccion ocular)
- Usuarios en contextos situacionales (sol en la pantalla, manos ocupadas)
- Usuarios mayores con vision o movilidad reducida
- Mejora el SEO y la usabilidad general
Ademas, en muchos paises la accesibilidad web es un requisito legal. La European Accessibility Act entra en vigor en junio de 2025, y la ADA en Estados Unidos ya ha generado miles de demandas por sitios inaccesibles.
WCAG 2.2: los cuatro principios
Las Web Content Accessibility Guidelines se organizan en cuatro principios fundamentales, conocidos como POUR:
1. Perceptible
El contenido debe poder ser percibido por todos los sentidos disponibles.
2. Operable
La interfaz debe poder ser operada por cualquier usuario con cualquier dispositivo de entrada.
3. Comprensible
El contenido y la interfaz deben ser comprensibles.
4. Robusto
El contenido debe ser interpretable por tecnologias asistivas actuales y futuras.
Checklist completa por categoria
Estructura y semántica
- Usar un único
<main>por página - Encabezados en orden jerarquico sin saltos (
h1->h2->h3) - Landmarks correctos:
<header>,<nav>,<main>,<aside>,<footer> - Listas semanticas para grupos de items (
<ul>,<ol>,<dl>) - Tablas con
<caption>,<thead>,<th scope="col|row"> - Idioma del documento declarado:
<html lang="es"> - Cambios de idioma marcados:
<span lang="en">Responsive design</span>
Imagenes y multimedia
- Todas las imagenes informativas tienen
altdescriptivo - Imagenes decorativas usan
alt=""oaria-hidden="true" - Graficos complejos tienen descripción larga con
aria-describedby - Videos tienen subtitulos
- Audio tiene transcripcion disponible
- Las animaciones se pueden pausar o desactivar
- Respetar
prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}Navegación por teclado
- Todos los elementos interactivos son alcanzables con Tab
- El orden de tabulacion es lógico y predecible
- El foco es visible en todo momento (
:focus-visible) - No hay trampas de teclado (el usuario puede salir con Tab/Escape)
- Existe un "Skip to content" link
- Los modales atrapan el foco correctamente (focus trapping)
- Escape cierra modales y popups
- Los shortcuts de teclado no interfieren con el navegador
Formularios
- Cada input tiene un
<label>asociado confor/id - Los grupos de inputs usan
<fieldset>y<legend> - Los campos requeridos tienen
aria-required="true"orequired - Los errores se anuncian con
aria-describedbyyaria-invalid - El autocompletado usa
autocompletecon valores correctos - Las instrucciones de formato estan visibles, no solo como placeholder
<div class="form-group">
<label for="email">Correo electronico</label>
<input
id="email"
type="email"
required
autocomplete="email"
aria-describedby="email-help email-error"
/>
<p id="email-help" class="hint">Ejemplo: [email protected]</p>
<p id="email-error" class="error" role="alert" aria-live="assertive">
<!-- Mensaje de error dinámico -->
</p>
</div>Color y contraste
- Ratio de contraste mínimo 4.5:1 para texto normal (AA)
- Ratio de contraste mínimo 3:1 para texto grande (24px+ o 19px+ bold)
- Ratio de contraste mínimo 3:1 para componentes de UI y graficos
- La información no se transmite solo por color
- Funciona correctamente en modo de alto contraste
Verificar contraste programaticamente
// Calcular ratio de contraste entre dos colores
function contrastRatio(luminance1, luminance2) {
const lighter = Math.max(luminance1, luminance2);
const darker = Math.min(luminance1, luminance2);
return (lighter + 0.05) / (darker + 0.05);
}
function relativeLuminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c = c / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}Contenido dinámico y ARIA
- Los cambios dinámicos se anuncian con
aria-live - Los estados de carga usan
aria-busy="true" - Los tabs usan roles
tablist,tab,tabpanel - Los accordions usan
aria-expanded - Los menus usan roles
menu,menuitem - Los tooltips se vinculan con
aria-describedby - Los botones de toggle usan
aria-pressed
<!-- Tabs accesibles -->
<div role="tablist" aria-label="Secciones del curso">
<button role="tab"
id="tab-1"
aria-selected="true"
aria-controls="panel-1">
Leccion 1
</button>
<button role="tab"
id="tab-2"
aria-selected="false"
aria-controls="panel-2"
tabindex="-1">
Leccion 2
</button>
</div>
<div role="tabpanel"
id="panel-1"
aria-labelledby="tab-1">
Contenido de la leccion 1...
</div>
<div role="tabpanel"
id="panel-2"
aria-labelledby="tab-2"
hidden>
Contenido de la leccion 2...
</div>Manejo de foco en SPAs
En aplicaciones de una sola página (SPA), el manejo del foco es crítico:
// Angular: mover el foco al contenido principal despues de navegar
import { Router, NavigationEnd } from '@angular/router';
import { inject } from '@angular/core';
export class AppComponent {
private router = inject(Router);
constructor() {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
const main = document.querySelector('main');
if (main) {
main.setAttribute('tabindex', '-1');
main.focus();
}
}
});
}
}Herramientas de testing
Automatizadas
| Herramienta | Tipo | Cobertura |
|---|---|---|
| axe DevTools | Extension de navegador | ~57% de issues WCAG |
| Lighthouse | Chrome DevTools | Auditoria general |
| pa11y | CLI / CI | Automatizacion |
| eslint-plugin-jsx-a11y | Linter | Prevencion en código |
| jest-axe | Testing unitario | Tests automatizados |
Testing manual imprescindible
Las herramientas automatizadas solo detectan el 30-50% de los problemas de accesibilidad. El testing manual es obligatorio:
- Navegar solo con teclado: Tab, Shift+Tab, Enter, Espacio, Escape, flechas
- Usar un lector de pantalla: NVDA (Windows), VoiceOver (Mac/iOS), TalkBack (Android)
- Verificar con zoom al 200%: todo debe ser funcional y legible
- Probar sin colores: usar extensión de simulacion de daltonismo
- Verificar en modo de alto contraste: Windows High Contrast Mode
Los 10 errores más comunes
- Imagenes sin atributo
alt - Formularios sin labels asociados
- Contraste insuficiente
- No hay indicador de foco visible
- Links genericos como "click aquí" o "leer más" sin contexto
- Contenido solo accesible con mouse (hover)
- Modales sin focus trapping
- No hay skip link
- Videos sin subtitulos
- Uso incorrecto de ARIA (peor que no usar ARIA)
Conclusion
La accesibilidad web no es una fase del desarrollo, es una filosofia de diseño. Cada decision, desde la estructura HTML hasta los colores y las interacciones, impacta en la experiencia de millones de personas. Esta checklist es un punto de partida solido, pero la verdadera accesibilidad viene de empatizar con tus usuarios y probar continuamente con personas reales y tecnologias asistivas.



Comentarios (0)
Inicia sesión para comentar