Volver al blog
accesibilidadWCAGARIA

Cómo hacer accesibles los botones de icono con aria-label

Los botones de icono están en todas partes: cierran diálogos, abren menús, envían búsquedas, cambian al modo oscuro. Para los usuarios videntes se ven limpios y familiares. Pero para alguien que usa un lector de pantalla, un botón que contiene solo un icono SVG es completamente silencioso. Sin etiqueta, sin contexto, sin forma de saber qué hace.

Es uno de los fallos de WCAG 2.1 más comunes en la web, y también uno de los más fáciles de corregir.

Por qué los botones de solo icono fallan en accesibilidad

Cuando un lector de pantalla encuentra un botón, anuncia el nombre accesible del botón: el texto que describe qué hace. Ese nombre puede provenir de varios lugares, y el navegador los resuelve con una prioridad definida. Una referencia aria-labelledby gana primero, luego aria-label, luego el propio contenido de texto del botón y, solo como último recurso, un elemento <title> dentro del SVG.

Un botón de icono que no tiene ninguno de estos no le da nada con qué trabajar al lector de pantalla. En la práctica, el lector puede anunciar “botón” y detenerse ahí, o recurrir a algo derivado de la estructura interna del SVG: un genérico “icono” o, en algunos casos, el contenido de un <title> que nunca quisiste exponer.

Esto incumple el Criterio de Conformidad 4.1.2 (Nombre, Función, Valor) en el Nivel A, el requisito mínimo de conformidad. Aquí no hay zona gris. Un botón sin nombre accesible falla, sin matices.

La solución: aria-label

La solución más rápida y portable es aria-label. Se agrega directamente al elemento <button> con una descripción corta y orientada a la acción de lo que hace el botón.

<!-- Antes: invisible para los lectores de pantalla -->
<button>
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

<!-- Después: botón de icono accesible -->
<button aria-label="Cerrar diálogo">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

Aquí importan dos detalles. Primero, aria-label va en el <button>, no en el SVG. El botón es el elemento interactivo, así que ahí es donde corresponde el nombre accesible. Segundo, aria-hidden="true" en el SVG evita que el lector de pantalla lea también lo que hay dentro de él (trazos decorativos, algún <title> perdido). El focusable="false" es un arreglo heredado para IE11 y el Edge antiguo, donde los SVG en línea recibían foco por defecto; en los navegadores actuales no hace nada, pero es inofensivo dejarlo.

Un punto que conviene tener claro: aria-label sobrescribe cualquier texto visible del botón, por lo que pasa a ser el único nombre que recibe el lector de pantalla. Mantenlo orientado a la acción: “Cerrar diálogo”, no “X” ni “Icono de cerrar”.

Cuándo aria-label no es la opción correcta

aria-label funciona bien para botones de icono autocontenidos, pero tiene un inconveniente: la etiqueta vive solo en el atributo, invisible en la página renderizada, así que se desincroniza en cuanto alguien actualiza el texto visible y olvida la cadena oculta. Cuando un botón está junto a un texto que ya dice lo que hace, aria-labelledby resulta más limpio. Apunta a ese texto existente mediante su ID, de modo que hay una sola fuente de verdad.

<span id="menu-label">Menú principal</span>
<button aria-labelledby="menu-label">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

Usa aria-labelledby cuando el texto de la etiqueta ya está renderizado en el DOM. Usa aria-label cuando el significado del botón es claro por contexto y no hay texto visible al cual referenciar.

El enfoque de texto visualmente oculto

Un tercer enfoque que muchos sistemas de diseño usan es el texto visualmente oculto — contenido de texto real posicionado fuera de pantalla para que sea invisible pero aún leído por la tecnología de asistencia.

<button>
  <svg aria-hidden="true" focusable="false">...</svg>
  <span class="sr-only">Abrir menú de navegación</span>
</button>
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

La ventaja es que la etiqueta es contenido real del DOM, no un atributo, así que sobrevive incluso donde el soporte de ARIA es irregular y fluye por los procesos de traducción que muchas veces ignoran los valores de atributos. El inconveniente está en el CSS: si las reglas de recorte quedan mal, el texto vuelve a aparecer en pantalla o se reduce a nada para el lector de pantalla. Copia un .sr-only ya probado de una utilidad confiable en lugar de escribir el tuyo desde cero.

¿Qué pasa con las etiquetas basadas en tooltips?

Una suposición común es que un tooltip al pasar el cursor cuenta como etiqueta. No es así. Un tooltip dibujado como un <div> con estilos al pasar el cursor es pura decoración para el árbol de accesibilidad; nunca se convierte en el nombre accesible del botón a menos que lo conectes de forma explícita con aria-labelledby (para nombrar el botón) o aria-describedby (para describirlo). Y los tooltips que solo aparecen al pasar el cursor jamás llegan a los usuarios de teclado o de lector de pantalla.

Los tooltips sirven para dar contexto adicional. No reemplazan a un nombre accesible.

Probando botones de icono accesibles

Una vez que se han agregado las etiquetas, hay que verificarlas:

  • Prueba con lector de pantalla: Navega al botón con Tab usando VoiceOver (Mac), NVDA (Windows) o TalkBack (Android). Deberías escuchar la etiqueta leída claramente.
  • Árbol de accesibilidad: Abre DevTools, ve al panel de Accesibilidad y haz clic en el elemento del botón. El campo “Accessible Name” debe mostrar tu texto de etiqueta — no estar en blanco, no decir “button”.
  • Análisis automatizado: Herramientas como axe o Lighthouse marcarán los botones con nombres accesibles vacíos como violaciones. Úsalos como punto de partida.

El problema con las tres es el bucle manual: abrir DevTools, cambiar de panel, hacer clic en un elemento, leer el campo, repetir. En una página con docenas de botones de icono eso se vuelve tedioso rápido, y lo tedioso es justo donde se cuelan los botones sin etiqueta.

Las herramientas de accesibilidad de PxGuard muestran atributos ARIA, nombres accesibles e información de rol directamente en una superposición sobre la página — para que puedas ver de un vistazo qué botones tienen etiquetas y cuáles no, sin salir de la pestaña del navegador.

Esto se combina bien con el flujo de trabajo de verificación WCAG en 5 minutos si quieres un repaso más rápido, y con el verificador de contraste de color para detectar los otros fallos comunes de Nivel A al mismo tiempo.

Una lista de verificación antes de publicar

  • Cada <button> de solo icono tiene un nombre accesible (mediante aria-label, aria-labelledby o texto visualmente oculto).
  • Los iconos SVG dentro de los botones tienen aria-hidden="true" para que el lector de pantalla no lea también las partes internas del SVG.
  • Las etiquetas describen la acción (“Cerrar diálogo”), no la forma (“Botón X”).
  • Lo revisaste con al menos un lector de pantalla real, no solo con un analizador automatizado.
  • Ningún botón depende de un tooltip como su única etiqueta.

Los botones de icono son una porción mínima de la página con un efecto enorme sobre si se puede usar sin mouse. Cinco minutos de etiquetado rinden para cada usuario de teclado y de lector de pantalla que llegue a tu sitio.

Instala PxGuard gratis →

Pruébalo en tus propias páginas

PxGuard es una extensión de Chrome gratuita. Inspecciona espaciado, tipografía y accesibilidad en segundos.

Instalar gratis