ARIA

Accessible Rich Internet Applications — semántica accesible para interfaces web

Por Yapci Bello ·

Conjunto de atributos HTML que describen roles, estados y propiedades de un componente para las tecnologías de apoyo. La primera regla de su especificación es no usarlo si existe un elemento HTML nativo que ya haga el trabajo.

Qué es ARIA

ARIA —Accessible Rich Internet Applications— es un conjunto de atributos que se añaden al HTML para describir qué es un elemento, en qué estado está y qué relación tiene con otros. Su público no son los ojos: es el árbol de accesibilidad, la representación de la página que consumen las tecnologías de apoyo.

El problema que resuelve es concreto. HTML tiene elementos para lo clásico: botones, enlaces, campos de formulario, tablas, listas. No tiene elementos para un carrusel, un árbol desplegable, un panel de pestañas o un combo de autocompletado. Cuando construyes uno de esos, el navegador ve un montón de div y span sin significado, y eso es exactamente lo que anuncia. ARIA permite decirle: esto es una pestaña, este panel le corresponde, esta está seleccionada.

Los atributos se agrupan en tres familias:

  • Roles — qué es la cosa: role="dialog", role="tab", role="alert".
  • Estados — qué le pasa ahora y puede cambiar: aria-expanded, aria-checked, aria-disabled, aria-invalid.
  • Propiedades — características más estables: aria-label, aria-labelledby, aria-describedby, aria-controls.

La primera regla: no usar ARIA

La especificación del W3C empieza con una advertencia que conviene tatuarse: si existe un elemento HTML nativo que ya hace el trabajo, úsalo y no pongas ARIA. Un <button> es preferible a un <div role="button"> en todos los casos sin excepción.

La razón es que ARIA solo cambia lo que se anuncia, no lo que se puede hacer. No añade comportamiento. Un div con role="button" sigue sin ser alcanzable con el tabulador, sigue sin activarse con Enter ni con la barra espaciadora, y sigue sin comportarse como un botón en el formulario. Para igualar a un <button> real hay que añadirle tabindex, gestores de teclado para dos teclas distintas, estilos de foco y el estado deshabilitado a mano. Y todo eso hay que mantenerlo.

De ahí sale la frase que repito en cada revisión de código: ARIA mal puesto es peor que no poner nada. Sin ARIA, un elemento raro se anuncia como texto y la persona al menos percibe que hay algo ahí. Con un rol mentiroso, se anuncia como un botón que no funciona, y eso no es una limitación: es una trampa.

Los cuatro usos que sí valen la pena

Después de descartar todo lo que HTML ya resuelve, queda un núcleo de casos donde ARIA es imprescindible.

Nombrar lo que no tiene texto visible. Un botón que solo contiene un icono necesita aria-label. Dos navegaciones en la misma página se distinguen con aria-label="principal" y aria-label="pie". Si hay texto visible que ya sirve de nombre, aria-labelledby es mejor que repetirlo.

Comunicar estados que cambian. Un desplegable necesita aria-expanded que pase de false a true al abrirse. Es de los atributos más útiles y de los que más veces encuentro puestos como valor fijo en el HTML, sin que ningún JavaScript los actualice nunca.

Anunciar lo que ocurre sin recargar la página. Los avisos de «producto añadido», «formulario enviado» o «tres resultados encontrados» solo llegan a quien no ve la pantalla si están dentro de una región con aria-live, o en un contenedor con role="alert" para lo urgente.

Describir relaciones. aria-describedby conecta un campo con su texto de ayuda o con su mensaje de error, de forma que se anuncian juntos al llegar al campo.

Lo que veo cuando reviso código

Cuando abro el inspector de una web con problemas, ARIA me da una lectura rápida de cómo se ha trabajado. Y hay un contraste que se repite: las webs con más atributos ARIA suelen ser las más inaccesibles. No es casualidad. La proliferación de atributos es lo que ocurre cuando alguien intenta parchear un marcado que no se apoya en HTML semántico.

El caso que más veces he desmontado es el menú de navegación. Alguien montó los enlaces con div, luego añadió role="menu" y role="menuitem" porque suena a menú, y con eso convirtió una navegación normal en un widget de aplicación que un lector de pantalla anuncia con reglas de teclado que nadie ha implementado. Ese ARIA se arregla borrándolo: una lista de enlaces dentro de un <nav> es más accesible y menos código.

El segundo caso es el modal. role="dialog" y aria-modal="true" puestos, y detrás nada: el foco no entra al abrirse, se puede tabular fuera hacia la página que está debajo, Escape no cierra y al cerrar el foco no vuelve al botón que lo abrió. Los atributos anuncian un diálogo; el comportamiento es el de una capa flotante cualquiera.

Al maquetar este sitio la regla fue la contraria: usar HTML nativo hasta que deja de dar, y solo entonces añadir el atributo mínimo. La evidencia de lo que se ha comprobado está en la declaración de accesibilidad.

Por qué le importa a un negocio

Porque es donde se rompe la compra. Los componentes que llevan ARIA son precisamente los interactivos: filtros, selectores, carritos, formularios de varios pasos. Si fallan, no pierdes matices de experiencia: pierdes la transacción entera.

Porque las herramientas automáticas no lo cubren bien. Un validador detecta un rol mal escrito o un aria-labelledby que apunta a un identificador inexistente. No detecta que el rol es mentira, ni que el estado no se actualiza, ni que el nombre accesible no describe lo que hace el botón. Esa parte hay que probarla con el teclado y con el árbol de accesibilidad delante.

Porque el HTML semántico que sustituye a ARIA es el mismo que ayuda al posicionamiento. Un rastreador tampoco ve el diseño: lee estructura. Cambiar div por elementos con significado mejora las dos cosas a la vez, algo que desarrollo en la sección de SEO.

Errores frecuentes

role="button" sobre un div. Es el error insignia. Anuncia un botón que no se puede alcanzar con el tabulador ni activar con el teclado. La solución no es añadir más atributos: es usar <button>.

Poner aria-expanded y no actualizarlo. Si el valor está escrito fijo en el HTML y el JavaScript solo cambia una clase CSS, el estado anunciado es siempre el mismo. La persona oye «contraído» con el menú abierto delante.

Duplicar el nombre accesible. Un aria-label sobre un elemento que ya tiene texto visible sustituye a ese texto. Si no coinciden, quien usa control por voz dice en alto lo que lee y no pasa nada, porque el nombre real es otro.

Usar aria-hidden para ocultar cosas visibles. aria-hidden="true" no oculta a la vista: oculta al árbol de accesibilidad. Puesto sobre contenido que se ve, crea elementos que existen para unos usuarios y no para otros. Y si dentro hay algo enfocable, se llega a ello con el tabulador sin que se anuncie nada.

Copiar un patrón del APG a medias. Las guías de autoría del W3C describen roles, estados y el comportamiento de teclado que los acompaña. Coger los atributos y dejar el teclado fuera produce justo el componente mentiroso que más daño hace.

Dónde trato ARIA a fondo

¿Quieres que lo implementemos por ti?

Yo diseño la estrategia; la ejecuta mi equipo en SMedialab, la agencia que cofundé en Tenerife.

Ir a SMedialab →

Buscador del sitio

Escribe al menos dos letras para buscar.