Hermano estructural de El navegador ya tiene una arquitectura. La mayoría de los proyectos la ignoran: la misma distinción, en una capa diferente.
También disponible en Inglés
El problema
Una auditoría de accesibilidad da un resultado limpio. Cada control interactivo tiene un role. Cada icono tiene una etiqueta. El escáner automatizado muestra una puntuación aprobatoria y el equipo continúa.
Luego, un usuario de lector de pantalla intenta cerrar un panel de navegación. Escucha "Descartar panel de navegación" anunciado en un elemento que dice visiblemente "Cerrar menú". Nada se interrumpe. El control sigue funcionando; presionar Enter todavía cierra el panel. Pero el usuario al que se le dijo que escuchara "Cerrar" escuchó algo completamente diferente y tuvo que adivinar.
Nadie eliminó una etiqueta. Alguien agregó una, específicamente para que el escáner dejara de señalar el control como no etiquetado. La auditoría se volvió más silenciosa. El control se volvió más difícil de usar.
Por qué existe el problema
Las herramientas de accesibilidad existen porque los fallos de accesibilidad son, de otro modo, invisibles para la mayoría de las personas que construyen un producto. Una etiqueta faltante, un role que nadie definió, un orden de enfoque (focus) que atrapa a un usuario de teclado: nada de eso aparece en una revisión visual de QA. Los escáneres automatizados y las listas de verificación de cumplimiento surgieron para detectar exactamente ese punto ciego, y detectan una categoría real de fallo: un botón compuesto solo por un icono que un lector de pantalla anuncia simplemente como "botón".
Para esa categoría específica, aria-label existe por una razón real. Un control de solo icono —un glifo de papelera sin texto visible— no le da al navegador nada a partir de lo cual calcular un nombre. No hay contenido para que el cálculo del nombre accesible lea. aria-label llena un espacio que de otro modo permanecería vacío.
El problema comienza cuando la misma lista de verificación que señala correctamente un botón de icono sin etiqueta también señala un <button> que ya tiene texto visible, y la solución aplicada es idéntica en ambos casos: agregar un aria-label. Uno de esos elementos no tenía nada con qué trabajar. El otro ya tenía un nombre. La lista de verificación no distingue entre los dos casos porque, desde la perspectiva del escáner, ambos solo necesitaban un aria-label para dejar de ser señalados.
El primer principio
El navegador no espera a que ARIA le diga qué es algo. Los elementos HTML nativos ya llevan funciones (roles) y comportamientos implícitos: un <button> es un botón para el árbol de accesibilidad antes de que cualquier atributo lo toque, de la misma manera que ya es ejecutable mediante clic y enfocable antes de que cualquier JavaScript lo toque. El árbol de accesibilidad se deriva del propio HTML, el mismo documento que el navegador ya está procesando para todo lo demás.
Los nombres accesibles siguen su propia secuencia definida, verificada en orden: primero aria-labelledby, luego aria-label, después el propio contenido del elemento, y finalmente los fallbacks restantes. Un <button>Close menu</button> obtiene su nombre del tercer paso de esa lista, su contenido, porque no hay nada anterior en la secuencia que lo reclame primero. En el momento en que se agrega un aria-label, ese paso anterior gana en su lugar, y el contenido que un usuario vidente realmente lee nunca se llega a alcanzar.
ARIA no es una capa de accesibilidad separada sobre el DOM. Es un conjunto de entradas que el mismo cálculo ya ejecuta, uno que resulta tener prioridad sobre el contenido cuando está presente, independientemente de si el contenido ya estaba diciendo lo correcto.
Demostrando el principio
Un control compuesto solo por un icono, sin nada más que le dé nombre:
<button aria-label="Delete item">
<svg aria-hidden="true"><!-- trash can icon --></svg>
</button>
Nada aquí entra en conflicto con nada. El <svg> está oculto del árbol de accesibilidad, no hay contenido de texto para que el cálculo lo encuentre, y aria-label proporciona el único nombre disponible. Este es el caso para el que se creó ARIA.
Ahora el mismo atributo, en un control que ya tenía contenido:
<button aria-label="Dismiss navigation panel">
Close menu
</button>
Visualmente, nada cambió. Un usuario vidente todavía lee "Close menu". Programáticamente, el nombre accesible ahora es "Dismiss navigation panel". El contenido no desapareció del DOM. Simplemente dejó de ser lo que alcanza el cálculo del nombre, porque aria-label se sitúa antes en la secuencia y el cálculo se detiene en la primera coincidencia.
Mismo atributo. Misma sintaxis. Uno llena un espacio vacío. El otro reemplaza algo que ya era correcto.
El punto de dolor
Esto se envió a producción en un control de navegación global: un <button> nativo con texto visible que decía "Close menu". Una revisión de accesibilidad lo señaló durante una fase de cumplimiento, no porque careciera de nombre, sino porque la lista de verificación utilizada exigía un aria-label explícito en cada control interactivo, independientemente de si ya había uno disponible en el contenido. La etiqueta agregada fue "Dismiss navigation panel", escrita para ser más descriptiva que el propio texto corto del botón.
El control visible y el nombre programático ya no describían la misma cosa. Un usuario vidente lee "Close menu". Un lector de pantalla anuncia "Dismiss navigation panel". El software de control por voz que escucha la palabra que un usuario realmente puede ver —el mecanismo que el criterio Label in Name de las WCAG existe para proteger— no tiene nada con qué coincidir. El usuario dice "hacer clic en cerrar menú" a un control que, en lo que respecta al árbol de accesibilidad, ya no se llama así.
La misma revisión también agregó role="button" a un <div> en otra parte de la misma navegación, reemplazando a un segundo control que el equipo quería que se viera igual. El role es una declaración, no una transferencia. <div role="button"> le dice al árbol de accesibilidad que anuncie el elemento como un botón. No le otorga a ese <div> el manejo nativo de teclado de un botón, su comportamiento de enfoque predeterminado ni su activación integrada con Enter y Espacio, cosas que el <button> ya proporciona sin tener que pedírselo. El div se anuncia correctamente y no hace casi nada correctamente una vez que el teclado lo alcanza.
El Notas desde el Pase del sábado elimina el aria-label del control de navegación y observa cómo el nombre accesible vuelve a ser "Close menu" por sí solo, y luego verifica qué le falta realmente al <div role="button"> frente a lo que un <button> nativo habría proporcionado gratis.
La lección más amplia
Este no es un argumento contra aria-label, ni contra ARIA en general. El botón compuesto solo por un icono al principio de este artículo lo necesitaba; no había nada más que leer. El fallo aquí no fue usar el atributo. Fue usarlo sin verificar si el navegador ya tenía una respuesta.
Cada anotación agregada a un documento es una afirmación sobre lo que la plataforma aún no sabe. A veces esa afirmación es correcta: un icono sin texto realmente no tiene nada con qué nombrarse a sí mismo. A veces no lo es, y la anotación sobrescribe algo que el navegador ya estaba calculando correctamente, considerado presente en una lista de verificación de cualquier manera.
ARIA es una intervención semántica. Debe suministrar lo que el documento nativo no expresa por sí mismo, no reemplazar lo que sí expresa. La pregunta que vale la pena hacerse antes de agregar algo de esto no es si el control necesita más información de accesibilidad. Es si el navegador ya tiene la información y simplemente no se le ha preguntado aún.
Top comments (0)