En este artículo repasamos la accesibilidad web desde el lado del desarrollo: qué añadió WCAG 2.2 respecto a 2.1, una checklist técnica que aplicamos en temas y bloques de WordPress, cómo auditar con axe, Lighthouse y un lector de pantalla, y dónde se cruzan accesibilidad y rendimiento. También tratamos los errores que más vemos: outline: none sin alternativa, iconos sin nombre accesible, formularios con el placeholder como única etiqueta, ARIA puesto «por si acaso» y botones demasiado pequeños en móvil.
WCAG en 30 segundos
Las WCAG (Web Content Accessibility Guidelines) son la recomendación del W3C para contenido web accesible. Se organizan en cuatro principios (perceptible, operable, comprensible y robusto), y cada criterio de conformidad tiene un nivel: A, AA o AAA. En la práctica, el objetivo habitual, y el que piden las normativas, es el nivel AA.
WCAG 2.2 es Recomendación del W3C desde el 5 de octubre de 2023. Es compatible hacia atrás: si cumples 2.2, cumples 2.1 y 2.0.
Qué añadió WCAG 2.2 respecto a 2.1
WCAG 2.2 añade nueve criterios y retira uno:
- 2.4.11 Foco no oculto (mínimo), AA: el elemento con foco no puede quedar totalmente tapado por contenido del autor, como una cabecera sticky o un banner de cookies.
- 2.4.12 Foco no oculto (mejorado), AAA: lo mismo, pero sin que quede tapado ni parcialmente.
- 2.4.13 Apariencia del foco, AAA: requisitos de tamaño y contraste del indicador de foco.
- 2.5.7 Movimientos de arrastre, AA: todo lo que se hace arrastrando (sliders, reordenar, mapas) debe poder hacerse con un solo puntero sin arrastrar, por ejemplo con clics o botones.
- 2.5.8 Tamaño del objetivo (mínimo), AA: los objetivos de puntero deben medir al menos 24×24 píxeles CSS, salvo excepciones (espaciado suficiente, enlaces dentro de un texto, controles nativos sin modificar, etc.).
- 3.2.6 Ayuda consistente, A: si ofreces mecanismos de ayuda (contacto, chat, FAQ), deben aparecer en el mismo orden relativo en todas las páginas.
- 3.3.7 Entrada redundante, A: no pedir al usuario dos veces el mismo dato en un mismo proceso; rellénalo automáticamente o permite seleccionarlo.
- 3.3.8 Autenticación accesible (mínimo), AA: el login no puede depender de una prueba cognitiva (recordar, transcribir, resolver un puzle) sin alternativa. Bloquear el pegado en el campo de contraseña o impedir los gestores de contraseñas incumple este criterio.
- 3.3.9 Autenticación accesible (mejorado), AAA: versión más estricta, sin excepciones para reconocer objetos o contenido propio.
El criterio 4.1.1 Análisis (Parsing) queda obsoleto y se elimina: los navegadores y las tecnologías de apoyo ya toleran los errores de marcado que motivaban esa regla. Eso no significa que el HTML inválido dé igual; los IDs duplicados siguen rompiendo relaciones como aria-labelledby o <label for>.
Checklist técnica para WordPress
Esta es la lista que repasamos al construir un tema o un bloque.
1. HTML semántico primero
- Un único
<h1>por página y encabezados sin saltos de nivel. En el editor de bloques es fácil elegir un h4 porque «se ve más pequeño»: el tamaño se cambia con CSS, no con el nivel. - Landmarks:
<header>,<nav>,<main>,<footer>. Si hay varios<nav>, dales un nombre conaria-label. <button>para acciones y<a href>para navegar. Un<div>cononclickno recibe foco ni responde a Enter y Espacio.- Atributo
langcorrecto en<html>(WordPress lo genera conlanguage_attributes()) ylangen los fragmentos en otro idioma. - Enlace para saltar al contenido como primer elemento enfocable.
<a class="skip-link screen-reader-text" href="#main">Saltar al contenido</a>
...
<main id="main" tabindex="-1">
La clase screen-reader-text es la convención de WordPress para ocultar visualmente un texto sin ocultarlo al lector de pantalla. El skip link debe hacerse visible cuando recibe el foco.
2. Contraste
- Texto normal: relación mínima de 4,5:1. Texto grande (24 px, o 18,66 px en negrita): 3:1.
- Componentes de interfaz y gráficos (bordes de inputs, iconos que transmiten información, indicador de foco): 3:1 frente a lo adyacente.
- Revisa los estados hover, disabled y los textos sobre imagen, que es donde suele fallar. Si defines la paleta en
theme.json, valídala una vez y los editores no podrán elegir combinaciones ilegibles.
3. Foco visible
El error clásico es un reset con outline: none. Usa :focus-visible para mostrar el foco al navegar con teclado sin molestar al hacer clic:
:focus-visible {
outline: 3px solid #1a5fb4;
outline-offset: 2px;
}
/* Que la cabecera sticky no tape el elemento enfocado (2.4.11) */
html {
scroll-padding-top: 5rem;
}
4. Navegación por teclado
- Recorre la página solo con Tab, Mayús+Tab, Enter, Espacio y Escape. El orden del foco debe seguir el orden visual.
- Evita
tabindexpositivos; usa0para hacer enfocable algo que no lo es y-1para enfocarlo solo por script. - Menús desplegables, modales y acordeones: Escape cierra, el foco no se escapa del modal mientras está abierto y vuelve al botón que lo abrió al cerrarlo. El elemento nativo
<dialog>conshowModal()resuelve gran parte de esto. - Si usas sliders o drag and drop, ofrece botones alternativos (2.5.7).
5. Textos alternativos
- Imagen informativa:
altque describa su función o contenido. Imagen decorativa:alt="", no omitir el atributo. - En WordPress el alt vive en la biblioteca de medios, pero en el tema hay que asegurarse de que se imprime;
wp_get_attachment_image()ya lo hace. - Botones solo con icono: necesitan un nombre accesible.
<button type="button" aria-label="Abrir menú" aria-expanded="false" aria-controls="menu-principal">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
6. Formularios
- Cada campo con su
<label>asociado. El placeholder no es una etiqueta: desaparece al escribir y suele tener poco contraste. - Agrupa radios y checkboxes con
<fieldset>y<legend>. - Usa
autocomplete(email,name,postal-code…) y lostypeadecuados; ayuda al criterio 1.3.5 y evita reescribir datos (3.3.7). - Errores en texto, junto al campo, enlazados con
aria-describedbyy marcados conaria-invalid="true". No basta con poner el borde en rojo. - Revisa los CAPTCHA del formulario y del login: un puzle sin alternativa choca con 3.3.8.
<label for="email">Correo electrónico</label>
<input id="email" name="email" type="email" autocomplete="email"
aria-invalid="true" aria-describedby="email-error">
<p id="email-error">Introduce un correo con el formato [email protected]</p>
7. ARIA solo cuando hace falta
La primera regla de ARIA es no usarla si existe un elemento HTML nativo que haga lo mismo. ARIA cambia lo que anuncia el lector de pantalla, pero no añade comportamiento: un role="button" sobre un <div> sigue sin responder al teclado. Donde sí aporta: estados (aria-expanded, aria-current="page" en el menú), nombres para controles sin texto y regiones dinámicas con aria-live="polite" para avisos como «producto añadido al carrito».
8. Tamaño de los objetivos táctiles
El mínimo AA de WCAG 2.2 es 24×24 px CSS. Iconos sociales, el aspa de cerrar y la paginación suelen quedarse cortos. Puedes ampliar el área de clic sin cambiar el diseño:
.icon-button {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
Usamos 44 px como objetivo cómodo; el mínimo AA es 24 px.
9. Movimiento y contenido multimedia
- Respeta
prefers-reduced-motionen animaciones y carruseles automáticos, y ofrece un control para pausar lo que se mueva más de cinco segundos. - Vídeos con subtítulos y, si hay información que solo se ve, transcripción o audiodescripción.
Cómo auditar
Ninguna herramienta automática cubre WCAG entera: detectan bien contraste, alt ausentes, etiquetas o IDs duplicados, pero no saben si un alt tiene sentido o si el orden del foco es lógico. Combinamos tres capas.
Paso 1: axe y Lighthouse
Lighthouse (en Chrome DevTools) usa el motor axe-core para su puntuación de accesibilidad: sirve como primer filtro, pero un 100 no significa que la página sea accesible. Para integrarlo en CI, por ejemplo con Playwright:
npm install -D @axe-core/playwright
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('home sin violaciones WCAG A/AA', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
.analyze();
expect(results.violations).toEqual([]);
});
Paso 2: teclado
Desenchufa el ratón y recorre las plantillas clave: portada, entrada, archivo, formulario de contacto, menú móvil y, si hay tienda, carrito y checkout. Comprueba que el foco siempre se ve, que no queda tapado por la cabecera y que no hay trampas.
Paso 3: lector de pantalla
Con NVDA en Windows o VoiceOver en macOS e iOS, navega por encabezados y landmarks, rellena un formulario con errores y abre un modal.
Accesibilidad y rendimiento
Van más de la mano de lo que parece:
- DOM más pequeño: el HTML semántico y sin capas de
<div>anidados pesa menos y genera un árbol de accesibilidad más simple. Lo contamos en cómo reducir el tamaño excesivo del DOM. - Menos JavaScript: los elementos nativos (
<button>,<details>,<dialog>) traen teclado y semántica sin librerías. Cada widget reescrito en JS es más código que descargar y más sitios donde romper la accesibilidad. Desde marzo de 2024 Core Web Vitals mide la respuesta con INP, así que un hilo principal saturado afecta igual al usuario de ratón que al de teclado o lector de pantalla; más en mejora de la capacidad de respuesta. - Imágenes: declarar
widthyheightevita saltos de maquetación (CLS) que hacen perder el punto de lectura, y el lazy loading nativo no afecta alalt. Ver optimizar imágenes en WordPress. - Animaciones: las que se basan en
transformyopacityson más baratas, y respetarprefers-reduced-motionahorra trabajo en dispositivos modestos. - Fuentes: con
font-display: swapel texto se lee desde el principio en lugar de quedar invisible mientras carga la fuente.
Ojo con los overlays de accesibilidad que se instalan con un script: añaden peso y peticiones de terceros y no corrigen los problemas del código.
Contexto legal en Europa
A título informativo: la Directiva (UE) 2019/882, conocida como European Accessibility Act, se aplica desde el 28 de junio de 2025 a ciertos productos y servicios, entre ellos el comercio electrónico y la banca, con exenciones para microempresas que prestan servicios. En España la transpone la Ley 11/2023. El sector público ya tenía obligaciones propias desde la Directiva (UE) 2016/2102. La norma técnica de referencia, EN 301 549 (versión 3.2.1), incorpora WCAG 2.1 AA, de modo que trabajar con WCAG 2.2 AA la cubre. Si un sitio concreto entra o no en su ámbito es una cuestión jurídica.
Resumen
Si solo te quedas con una cosa: HTML nativo y semántico, foco siempre visible, todo operable con teclado, etiquetas reales en los formularios y una auditoría que combine axe, teclado y lector de pantalla. Con eso se resuelve la mayor parte de WCAG 2.2 AA.