Una guía para desarrolladores sobre etiquetas ARIA que realmente ayudan
Las etiquetas ARIA no son una capa mágica de accesibilidad. Usadas bien, hacen que los controles sean comprensibles. Usadas sin cuidado, ocultan texto útil y crean interfaces confusas.
Tabla de contenido
- Las etiquetas ARIA son para nombres, no para disculpas
- El nombre accesible, en términos sencillos
- Primera regla: prefiere HTML nativo y etiquetas visibles
- Cuándo `aria-label` es la herramienta adecuada
- Cuándo `aria-label` es la herramienta equivocada
- Recurre a `aria-labelledby` cuando el texto visible ya existe
- Usa `aria-describedby` para texto de ayuda, no para el nombre
- Los controles repetidos necesitan nombres únicos
- No etiquetes todo
- Comprueba el nombre calculado, no solo el código
- Una lista de verificación práctica para revisión
- La disciplina silenciosa de un buen ARIA
Las etiquetas ARIA son para nombres, no para disculpas
ARIA es útil, pero a menudo se usa como un parche para HTML poco claro. Ahí es donde los equipos empiezan a tener problemas.
El ejemplo más común es aria-label. Parece inofensivo: añadir una cadena, satisfacer un linter y seguir adelante. Pero un nombre accesible no es decoración. Es el nombre que muchas tecnologías de asistencia exponen a los usuarios cuando navegan por botones, enlaces, campos de formulario, encabezados, puntos de referencia y controles.
Si ese nombre es vago, está duplicado, está desactualizado o es distinto de la etiqueta visible, la interfaz se vuelve más difícil de usar. A veces, incluso peor: aria-label puede sobrescribir texto mejor que ya estaba presente en el DOM.
El objetivo no es añadir más ARIA. El objetivo es hacer que el nombre, el rol, el estado y el propósito de cada elemento de la interfaz sean claros.
El nombre accesible, en términos sencillos
La mayoría de los elementos interactivos tienen un nombre accesible. Los lectores de pantalla usan ese nombre para anunciar qué es el elemento.
Por ejemplo:
<button>Save changes</button>
Un lector de pantalla puede anunciar algo como: “Save changes, botón”. El rol proviene del elemento nativo button. El nombre proviene del texto que contiene.
Ese es el caso ideal: el texto visible y el nombre accesible coinciden.
Los atributos de etiquetado ARIA son útiles cuando la interfaz visible no proporciona un nombre completo, o cuando el nombre debe provenir de otro elemento. Los atributos principales son:
aria-label: proporciona una cadena directamente en el elemento.aria-labelledby: apunta a uno o más elementos cuyo texto se convierte en el nombre.aria-describedby: apunta a texto descriptivo de apoyo, no al nombre principal.
Estos tres están relacionados, pero no son intercambiables.
Primera regla: prefiere HTML nativo y etiquetas visibles
Si puedes poner texto visible en el control, haz eso primero.
Esto es mejor:
<button>Delete invoice</button>
Que esto:
<button aria-label="Delete invoice">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
El segundo patrón es válido para un botón solo con icono. Pero si el diseño puede tolerar texto visible, el texto visible ayuda a todos: usuarios de lectores de pantalla, usuarios de reconocimiento de voz, personas con carga cognitiva, personas que escanean rápidamente y personas que usan herramientas de traducción.
Este es un tema recurrente en el trabajo de accesibilidad. El HTML nativo y las señales visibles resuelven más problemas que los metadatos ocultos. El mismo principio se aplica a la semántica de los botones en general; si tu equipo está auditando controles de interfaz, nuestra lista de verificación para botones web accesibles es un buen complemento para esta guía.
Cuándo aria-label es la herramienta adecuada
Usa aria-label cuando un elemento necesite un nombre accesible y no haya texto visible adecuado al que hacer referencia.
El caso clásico es un botón solo con icono:
<button aria-label="Search">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- icon -->
</svg>
</button>
Esto es razonable. El icono visible sugiere búsqueda, pero la ruta SVG en sí no proporciona un nombre fiable. aria-label proporciona uno.
Otros buenos casos incluyen:
- Un botón de cierre representado solo por una “X”.
- Un punto de referencia de navegación que necesita un nombre más específico, como
aria-label="Product". - Un control repetido donde el contexto visible no forma parte del texto del botón.
Por ejemplo:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
Ambos son puntos de referencia de navegación, pero sus etiquetas ayudan a los usuarios a distinguirlos cuando se desplazan por puntos de referencia.
Cuándo aria-label es la herramienta equivocada
No añadas aria-label solo porque una prueba diga que un elemento necesita una etiqueta. Corrige primero el marcado.
Mal:
<div role="button" tabindex="0" aria-label="Submit">Submit</div>
Mejor:
<button>Submit</button>
El primer ejemplo crea trabajo innecesario. Ahora tienes que recrear el comportamiento del teclado, los estados deshabilitados, el comportamiento de formulario y las expectativas que los botones nativos ya proporcionan.
Evita también usar aria-label para renombrar texto visible de una manera que cambie el significado.
<button aria-label="Delete invoice">Remove</button>
Esto parece menor, pero puede confundir a los usuarios que dependen de la entrada por voz. Si un botón visible dice “Remove”, pero su nombre accesible es “Delete invoice”, es posible que un usuario que intente decir “hacer clic en Remove” no obtenga el resultado esperado. El requisito de “etiqueta en el nombre” de WCAG existe exactamente por esta razón: el texto visible generalmente debería estar contenido en el nombre accesible.
Una versión mejor:
<button aria-label="Remove invoice">Remove</button>
A menudo, mejor aún:
<button>Remove invoice</button>
Recurre a aria-labelledby cuando el texto visible ya existe
Si el texto de la etiqueta ya está en la página, aria-labelledby suele ser mejor que aria-label.
Ejemplo:
<h2 id="billing-title">Billing address</h2>
<section aria-labelledby="billing-title">
...
</section>
El nombre accesible de la sección ahora proviene del encabezado visible. Evitas duplicar cadenas, lo que reduce errores de traducción y etiquetas desactualizadas.
Esto es especialmente útil para grupos de formularios:
<fieldset aria-labelledby="shipping-speed-title">
<legend id="shipping-speed-title">Shipping speed</legend>
<label>
<input type="radio" name="shipping" value="standard">
Standard
</label>
<label>
<input type="radio" name="shipping" value="express">
Express
</label>
</fieldset>
En muchos casos, el legend nativo es suficiente sin ARIA. La idea es que las etiquetas visibles deben guiar. ARIA debe conectar significado existente, no crear una segunda versión privada de él.
Usa aria-describedby para texto de ayuda, no para el nombre
Una descripción no es una etiqueta.
Considera este campo:
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-help">
<p id="password-help">Use at least 12 characters.</p>
El nombre accesible es “Password”. La descripción es “Use at least 12 characters.” Un lector de pantalla puede anunciar ambos, pero cumplen propósitos distintos.
No hagas esto:
<input type="password" aria-label="Use at least 12 characters">
Eso nombra el campo a partir de la instrucción, no del concepto. Un usuario que navega por un formulario quiere saber primero qué es el campo y luego qué restricciones se aplican.
Esta distinción también importa en los estados de error:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
La etiqueta se mantiene estable. El mensaje de error se convierte en contexto de apoyo.
Los controles repetidos necesitan nombres únicos
Las listas y las tarjetas son lugares donde las etiquetas ARIA a menudo se vuelven necesarias.
Mal:
<button>Delete</button>
<button>Delete</button>
<button>Delete</button>
Un usuario de lector de pantalla que navegue por botones puede oír “Delete, botón” tres veces sin contexto.
Bien:
<button aria-label="Delete report: Q4 revenue">Delete</button>
<button aria-label="Delete report: Hiring plan">Delete</button>
<button aria-label="Delete report: Vendor list">Delete</button>
Este es un uso legítimo de aria-label: el texto visible sigue siendo conciso, mientras que el nombre accesible incluye el objeto.
Pero usa este patrón con cuidado. Si el nombre del objeto es visible cerca, aria-labelledby puede ser más mantenible:
<article>
<h3 id="report-q4">Q4 revenue</h3>
<button aria-labelledby="delete-q4 report-q4" id="delete-q4">Delete</button>
</article>
El nombre accesible se convierte en “Delete Q4 revenue”. Esto evita duplicar el título del informe en un atributo.
No etiquetes todo
No todos los elementos necesitan una etiqueta ARIA.
El texto estático normalmente no la necesita. Los iconos decorativos no la necesitan. Los contenedores no la necesitan, a menos que tengan un rol significativo de punto de referencia o de widget. Etiquetar en exceso puede hacer que una página sea ruidosa y más difícil de navegar.
Para las imágenes, usa el modelo específico de imágenes: las imágenes significativas necesitan un alt útil; las imágenes decorativas necesitan un alt="" vacío. No uses etiquetas ARIA como sustituto de un buen texto de imagen. Si tu equipo está mezclando esos conceptos, revisa texto alternativo de imagen pragmático y separa las alternativas de imagen de los nombres de controles.
Un error común es dar a cada SVG un aria-label. Si el SVG está dentro de un botón y el botón ya tiene un nombre, normalmente el icono debería ocultarse a la tecnología de asistencia:
<button aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
De lo contrario, el usuario puede oír anuncios redundantes o extraños según la combinación de navegador y tecnología de asistencia.
Comprueba el nombre calculado, no solo el código
Los errores de accesibilidad a menudo sobreviven a la revisión de código porque el marcado parece plausible.
Las herramientas modernas para desarrolladores de los navegadores pueden mostrar el árbol de accesibilidad calculado. En Chrome, Edge, Firefox y Safari, inspecciona el elemento y busca información de accesibilidad como rol, nombre y descripción. Estás comprobando tres cosas:
- ¿El rol es el que esperas?
- ¿El nombre accesible es claro y específico?
- ¿La descripción ayuda sin reemplazar el nombre?
Después, prueba algunos flujos con un lector de pantalla real. No necesitas convertirte en especialista a tiempo completo en tecnología de asistencia para detectar lo básico. En macOS, VoiceOver viene integrado. En Windows, NVDA se usa ampliamente y es gratuito. En móvil, prueba con VoiceOver en iOS y TalkBack en Android cuando sea relevante.
Las herramientas automatizadas son útiles, pero no pueden decir de forma fiable si “Open”, “Read more” o “Delete” tienen suficiente contexto. Trata la automatización como una red, no como un juez. Esto es similar a auditar rendimiento: un informe puede señalar áreas sospechosas, pero aún necesitas interpretar el impacto. El mismo enfoque calmado que recomendamos para leer un informe de Lighthouse sin entrar en pánico se aplica aquí.
Una lista de verificación práctica para revisión
Antes de publicar etiquetas ARIA, pregunta:
- ¿Podría esto ser HTML nativo en su lugar?
- ¿Hay texto visible que debería usarse como etiqueta?
- Si existe texto visible, ¿el nombre accesible lo incluye?
- ¿Los controles repetidos son únicos cuando se navegan fuera del contexto visual?
- ¿El texto de ayuda está conectado con
aria-describedby, no forzado dentro de la etiqueta? - ¿Los iconos decorativos están ocultos a la tecnología de asistencia?
- ¿Alguien ha comprobado el nombre de accesibilidad calculado en las herramientas de desarrollo del navegador?
- ¿Se ha hecho al menos una pasada con un lector de pantalla real para el flujo crítico?
Esta lista de verificación detecta la mayoría de los problemas de etiquetado antes de que se conviertan en problemas para los usuarios.
La disciplina silenciosa de un buen ARIA
Un buen trabajo con ARIA rara vez es dramático. Es, sobre todo, contención.
Usa botones reales. Usa etiquetas reales. Mantén alineados los nombres visibles y accesibles. Añade aria-label solo cuando no haya una mejor fuente visible. Usa aria-labelledby cuando la página ya contiene el texto correcto. Usa aria-describedby para instrucciones de apoyo y errores.
La plataforma web da mucho gratis a los desarrolladores cuando la usamos directamente. ARIA está ahí para cubrir las brechas. La habilidad está en saber cuándo realmente hay una brecha.