"A11y" es abreviación de "accessibility" (11 letras entre la A y la y). No es un tema aparte del HTML/CSS que ya viste — es una capa que atraviesa todo: si usaste headings en orden, alt en las imágenes y label en los inputs, ya llevas gran parte del camino.
sr-only: visible solo para lectores de pantalla
A veces un elemento necesita texto que dé contexto pero que visualmente sería redundante o feo. sr-only lo oculta visualmente sin quitarlo del DOM ni del árbol de accesibilidad.
<button>
<svg><!-- ícono de basurero --></svg>
<span class="sr-only">Eliminar producto</span>
</button>
→sr-only es distinto de display: none o hidden: esos dos sí ocultan el contenido para TODOS, incluyendo lectores de pantalla.
→Tailwind incluye sr-only de fábrica — no hace falta escribir el CSS a mano (position absolute, width/height 1px, overflow hidden, etc).
aria-label vs aria-hidden
aria-label da un nombre accesible cuando no hay texto visible (ej: un botón que solo tiene un ícono). aria-hidden oculta un elemento decorativo del árbol de accesibilidad sin ocultarlo visualmente.
→El aria-hidden='true' en el SVG evita que un lector de pantalla intente describir el ícono decorativo (que ya está cubierto por el aria-label del botón).
→Nunca pongas aria-hidden='true' en un elemento que sí recibe foco de teclado — quedaría enfocable pero invisible para el lector de pantalla, una trampa de navegación.
Skip link: saltar al contenido principal
El primer elemento enfocable de la página. Permite a quien navega con teclado saltarse todo el header/nav repetitivo e ir directo al contenido, sin tener que tabular por cada link del menú en cada página.
Presiona Tab al cargar la página real → aparece "Saltar al contenido"
<a href="#main" class="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 focus:bg-white focus:px-4 focus:py-2 focus:rounded-lg focus:shadow-lg">
Saltar al contenido principal
</a>
...
<main id="main">...</main>
→focus:not-sr-only es el truco: el link está oculto normalmente, pero se vuelve visible en cuanto recibe foco (al presionar Tab) — así no molesta visualmente a nadie más.
Foco visible: nunca lo elimines sin reemplazo
focus-visible:outline-* asegura que cualquier elemento interactivo muestre claramente dónde está el foco del teclado — sin esto, alguien navegando sin mouse se pierde por completo.
→outline-none a secas (sin reemplazo) es de los errores de accesibilidad más comunes y más fáciles de evitar.
Contraste de color
El texto necesita suficiente contraste contra su fondo para ser legible, sobre todo para baja visión. WCAG AA pide mínimo 4.5:1 para texto normal y 3:1 para texto grande (18px+ bold, o 24px+).
Bajo contraste (evitar)
Buen contraste
<!-- Bajo contraste: difícil de leer -->
<p class="text-stone-300 bg-white">Texto gris claro sobre blanco</p>
<!-- Buen contraste -->
<p class="text-stone-700 bg-white">Texto legible</p>
→Herramientas como el inspector de Chrome DevTools (panel de colores) o contrastchecker.com calculan el ratio exacto entre dos colores.
Todo enfocable con teclado, en orden lógico
Cualquier elemento interactivo (links, botones, inputs) debe poder alcanzarse con Tab, en el mismo orden visual en que aparece en pantalla. tabindex mal usado rompe esa expectativa.
Orden del DOM = Orden de Tab
<!-- Evitar: reordena el flujo natural del DOM -->
<button tabindex="5">Primero visualmente, último en Tab</button>
<!-- tabindex="-1": saca del flujo de Tab pero permite foco programático (ej: al abrir un modal) -->
<div tabindex="-1" id="modal-title">...</div>
→Casi nunca deberías usar tabindex con números positivos — deja que el orden del DOM defina el orden de tabulación.