Cómo hicimos Yandex Cloud más accesible con el sistema de diseño Gravity UI

Hola, me llamo Vova Timoféyev y soy gerente de proyectos técnicos en Yandex Cloud. En este artículo compartiré cómo hicimos más accesible el sitio de la plataforma cloud, cuántas iteraciones pasamos y qué papel jugó Gravity UI en ello.

La base de la accesibilidad de todos los servicios es qué tan bien soportan el trabajo con lectores de pantalla (screen readers). A través de estos programas, las personas con limitaciones perciben la interfaz e interactúan con ella.

Los sitios web no son una excepción. Y nos tocaba averiguar qué tan accesible es Yandex Cloud para todas las personas usuarias.

En Yandex entendemos por accesibilidad que nuestros servicios deben poder usarse cómodamente por cualquiera, independientemente de limitaciones físicas temporales o permanentes. Por ejemplo, ahora mismo 16 servicios de Yandex están adaptados para personas ciegas: Lavka, Go, Búsqueda, Navegador, Correo y otros. En el trabajo de accesibilidad de cada servicio ayuda el equipo de pruebas no visuales; y en el caso del que hablaré en este artículo, tampoco podríamos haberlo hecho sin su ayuda.

Spoiler: como resultado de las pruebas se detectaron varios puntos discutibles al trabajar con lectores de pantalla, que se convirtieron en tareas reales.

Pero vayamos por partes.

Todo empezó con Gravity UI

Gravity UI es un sistema de diseño y una biblioteca de componentes sobre la que funciona el sitio de Yandex Cloud y decenas de otros productos de la nube. Está publicada como open source y está disponible para todo el mundo (nos alegra que en los últimos seis meses la actividad en el chat de la comunidad haya crecido notablemente).

Qué tenemos:

  • un conjunto de componentes base de React;
  • una biblioteca/constructor para landing pages;
  • guías detalladas de los diseñadores sobre el uso de componentes;
  • una biblioteca en Figma;
  • un set de casi 600 iconos listos;
  • ChartKit: un paquete para visualización de datos;
  • Yagr: renderizado de gráficos de alto rendimiento basado en uPlot;
  • i18n: un paquete para localización de la interfaz;
  • otras bibliotecas útiles.

En marzo de 2024 salió una actualización de la biblioteca clave: la versión 6 de UIKit. En ella se actualizó el componente List, apareció soporte del parámetro RTL en todos los componentes y un paquete de mejoras a11y para aumentar la accesibilidad.

Qué hay de nuevo en la versión 6 de UIKit
  1. Componente List 2.0. En UIKit originalmente existía List, pero queríamos mejorar algunas cosas. Al recopilar solicitudes, reunimos esta lista:

    • soporte para distintos tamaños y anchos;
    • icono en el elemento de lista, distinta cantidad y posición de iconos;
    • soporte de estados;
    • contenido diferente en los elementos de lista (de una línea, de varias líneas o lista de usuarios);
    • soporte para distintos tipos de separadores y agrupaciones.

    Son cambios importantes, por eso creamos List 2.0. Por ahora sale en versión prestable, pero recomendamos a las personas usuarias migrar a ella y traer feedback.

  2. RTL. Si vuestras apps o sitios deben mostrarse en hebreo, árabe u otros idiomas con escritura de derecha a izquierda, necesitáis soporte de estándares RTL. Además, en RTL:

    • una palabra insertada en alfabeto latino se escribe de izquierda a derecha;
    • los números se escriben de izquierda a derecha;
    • los signos de puntuación en árabe también se escriben de izquierda a derecha, etc.

    En todos los componentes soportamos el parámetro RTL. Para tener a mano un ejemplo completo, hicimos una página promocional en árabe. Se puede ver cómo está implementado en el código fuente de landing. También hay ejemplos en el storybook.

  3. Accesibilidad (a11y):

    • añadimos al proyecto el plugin de eslint;
    • añadimos soporte de teclado para los estados clickable y closable del componente Persona;
    • desactivamos onClick en 15 componentes no interactivos;
    • añadimos soporte de teclado en el componente SelectionTable.

Cómo llegamos a las mejoras a11y

En esto nos ayudó el equipo de pruebas no visuales y su líder, Anatoli Popko. En la reunión, Anatoli probó paso a paso el sandbox y el sitio de Gravity UI para entender qué problemas de accesibilidad existen ahora.

Comprobamos la accesibilidad de los componentes, moviéndonos por el sitio con el teclado y con comandos especiales de los lectores de pantalla.

Visualmente, se veía así:

Full screen image

Después de la reunión, el equipo obtuvo tareas de trabajo y, en GitHub, aparecieron tres nuevos issues sobre componentes base.

Más detalles:

  • En la lista desplegable, el segundo nivel de elementos
    no se abre
    con el teclado, solo con clic del ratón.
Full screen image
  • No queda claro qué elemento en una lista con viñetas en markdown está seleccionado en el componente Select.

  • Los botones sin etiquetas de texto, marcados solo gráficamente, se reproducen como simplemente “botón” o “botón de opción”. Este bug aparece solo en la landing; el componente en sí soporta aria-label, pero no lo usamos.

Full screen image

Como resultado, entendimos que, si no encontramos decenas de observaciones, la accesibilidad de la biblioteca ya está a un nivel bastante bueno. Probar componentes fuera de un contexto real es muy difícil; por eso decidimos empezar a comprobar la accesibilidad de un producto listo. Así pudimos encontrar mejoras a11y adicionales.

Accesibilidad de Yandex Cloud

Inspirados por la actualización de Gravity UI, decidimos probar la accesibilidad de nuestros servicios: empezar por el sitio de Yandex Cloud y, después, extender esta experiencia a otras interfaces.

Existe una serie de estándares; siguiéndolos, se puede lograr accesibilidad. Pero para probar de forma fiable las interfaces de Yandex Cloud y entender mejor qué tan cómodo es nuestro sitio para todo el mundo, realizamos una auditoría.

Auditoría de accesibilidad

Volvimos a recurrir a colegas del equipo de pruebas no visuales y a Anatoli para probar el sitio juntos, registrar problemas y llevarlos a implementación. En total hubo dos iteraciones con casi un mes de diferencia: prueba y reprueba (retest).

Durante las pruebas registramos todo un conjunto de correcciones que había que poner en marcha.

En la página principal

  • El control de búsqueda necesitaba rediseño. En nuestra interfaz, el componente de búsqueda está implementado como una zona de búsqueda con un icono de lupa. Al hacer clic en ellos, se abre el campo para introducir la consulta. En la implementación anterior, para el lector de pantalla eran elementos independientes, lo que confundía a las personas ciegas.

    image

  • En la selección de idioma utilizamos el atributo de estado “contraído”, aunque en esencia era un botón de selección y no una lista desplegable. No había una etiqueta “idioma”; faltaba un espacio en la transición “idioma — región”.

  • En el menú de la cuenta no se bloqueaba el foco: al activarlo, la persona usuaria salía fuera de los elementos del menú.

  • La etiqueta main se duplicaba en la página principal, así que había que eliminar una.

  • Sección con ejemplos: era necesario usar una pestaña (tab) en lugar de un botón.

Full screen image
  • En la tarjeta de ejemplo, el texto se había metido en aria-describedby; por eso el lector de pantalla leía el texto una sola vez, lo cual es incómodo al estudiar información importante. Cuando investigamos el bug, entendimos que valía la pena hacer un refactor integral del componente Card y creamos un issue donde se pueden ver los detalles de los cambios y participar en su discusión.
  • Problema de foco: al desplegar el nivel superior del menú, hay que mover el foco al submenú.
  • Era necesario eliminar TabIndex del nivel superior del menú. La forma actual provocaba que se enumeraran dos veces todos los elementos del menú.
  • Había que bloquear el foco del teclado en la navegación si está desplegada. De lo contrario, se puede “salir” del menú hacia la página y luego no poder volver.
  • Yandex Cloud estaba envuelto en una lista. Los encabezados de las listas de enlaces en el footer estaban envueltos en un elemento de lista, por lo que NVDA los detectaba como parte y leía la misma lista dos veces a la persona usuaria.
  • Faltaban etiquetas para los enlaces a AppStore y Google Play. En el momento de la prueba se leían fragmentos de la URL, lo cual no le aclaraba nada a la persona usuaria.

Sección “Blog”

  • Los botones “Todos los temas” y “Todos los servicios” no estaban correctamente asociados como botones. Los botones de los selects no anunciaban su contenido.
  • Se necesitaba soporte de accesibilidad en listas: al abrir una lista desplegable, el foco del lector de pantalla debe cambiar a los elementos de esa lista. Además, debe soportar un desplazamiento simplificado entre ellos con las flechas normales, sin usar combinaciones de teclas.

Artículos del blog

  • En las migas de pan faltaba el elemento “Usted está aquí”.
  • Había que bloquear el foco en el diálogo.
  • El contador de favoritos no tenía nombre. El contador era un botón con icono y número. Los lectores de pantalla leían el número; sin el icono no quedaba claro qué hacía el botón.

Reunimos todas las tareas en un epic y empezamos a trabajar. Para parte de las tareas se crearon issues en GitHub.

A continuación, contaré con más detalle los casos más interesantes.

Componente Select

Full screen image

Durante las pruebas descubrimos que, al navegar con el teclado, el lector de pantalla no anuncia los nombres de los elementos de la lista. En parte logramos corregir el problema con el atributo aria-activedescendant, pero no por completo.

Qué problemas permanecieron

  • En Safari este método no funciona, y por ahora no está claro cómo resolverlo.

  • No siempre se soporta el filtro de búsqueda (en realidad nunca; simplemente no está implementado). Normalmente aria-activedescendant se cuelga del elemento principal de la lista desplegable y apunta al elemento seleccionado. Ahora se cuelga del botón que abre la lista desplegable. Al pulsar flecha arriba o abajo, cambiamos en el botón el valor de aria-activedescendant al elemento anterior o siguiente de la lista. Así el lector de pantalla puede leer desde el botón qué elemento está seleccionado.

    El problema con el filtro de búsqueda es que su campo de entrada no tiene el atributo aria-activedescendant. Si alguien enfoca el campo de entrada del filtro y quiere escribir algo, el lector de pantalla no puede leer desde ahí qué elemento de la lista está activo, y la navegación por la lista con flechas no funciona.

  • Las opciones seleccionadas no están marcadas; es necesario añadirles un atributo, por ejemplo aria-selected.

El issue con los problemas actuales se puede ver aquí.

Migas de pan

Full screen image

Las migas de pan (Breadcrumbs) son un elemento de navegación que muestra el recorrido del usuario por el sitio. En nuestro caso, el lector de pantalla leía todo el recorrido y era imposible entender en qué parte del sitio se encontraba la persona. Además, todo el componente se presentaba simplemente como un conjunto de enlaces.

Decidimos apartarnos de los estándares y resolverlo de una manera simple y óptima: colgando para el lector de pantalla la etiqueta “Usted está aquí”. Al final combinamos el enfoque estándar y la etiqueta.

En el proceso se aclaró lo siguiente: para que esta etiqueta se lea, hay que colgarla de un elemento que los lectores de pantalla no ignoren. Fue más sencillo adjuntar la etiqueta a una estructura convencional que inventar una forma de evitarla. Aun así, la etiqueta sigue siendo útil: ayuda a la persona usuaria a entender más rápido que lo que está oyendo son precisamente las migas de pan.

Imágenes sin descripción

Algunas imágenes del sitio estaban colocadas sin descripciones, y el lector de pantalla las leía como “Imagen”. Esta información no aporta nada útil y no da una idea de la interfaz, así que decidimos ocultar las imágenes sin descripción al lector de pantalla.

Orden del texto en los bloques

Full screen image

En varios lugares de nuestro sitio, la información se presenta como un bloque único, por ejemplo, la tarjeta de un evento o la tarjeta de un artículo en el blog.

Observamos que los lectores de pantalla leen la información en un orden distinto al de las personas videntes. En la tarjeta del evento, el lector de pantalla leía así: estado de registro, hora, lugar y solo después el título y la descripción del evento.

Normalmente la persona usuaria no sigue un camino lineal: mira el título, luego el subtítulo y la imagen. El problema es que el lector de pantalla lee los elementos en el orden en que están ubicados en el árbol DOM de la página. Para corregir el orden, tuvimos que rearmarlo.

Full screen image

Nos sorprendió, pero en algunas combinaciones “sistema operativo — navegador” esto no funcionó. Por ejemplo, en Mozilla Firefox en macOS el problema se mantuvo, pese al cambio de orden en el árbol DOM. Esperemos que el equipo de Firefox corrija este comportamiento en versiones nuevas del navegador.

Ventanas modales

Full screen image

Cuando una persona vidente abre una ventana emergente en la interfaz, su mirada se centra en lo que hay dentro de esa ventana. Sin embargo, el contenido de todo el sitio sigue estando disponible, y si hace falta puede volver a prestarle atención.

Cuando se usa el sitio con un lector de pantalla, la situación cambia. Si la ventana emergente no es modal, no tendrá límites. Como resultado, navegar por el sitio se vuelve más difícil: la persona puede salir de la ventana emergente por error usando la navegación por elementos.

Para trabajar con ventanas modales existe un estándar, y si se sigue, no es obligatorio bloquear todas las ventanas emergentes de la interfaz.

Pero durante las pruebas llegamos a la conclusión de que hacer modales las ventanas emergentes es una buena práctica que simplifica el trabajo con el sitio cuando se usa un lector de pantalla.

Decidimos hacer modales todas las ventanas emergentes. Al mismo tiempo, dejamos la posibilidad de configurar un escenario alternativo de trabajo con este tipo de ventanas.

Se puede configurar asignando role="dialog", aria-modal="true". En la combinación VoiceOver + Firefox esta solución no está soportada: los detalles están en el issue cerrado aquí.

Diplodoc

Impulsados por nuestra actividad, los desarrolladores de la plataforma para crear documentación técnica Diplodoc realizaron una serie de mejoras a11y en su producto:

  • Revisaron todos los elementos adicionales de sintaxis de YFM (Yandex Flavored Markdown) y los reescribieron para que fueran visibles para los lectores de pantalla.
  • Mejoraron el flujo de trabajo con la documentación usando el teclado: corrigieron el orden de selección de elementos y añadieron la posibilidad de seleccionar para todos los elementos interactivos.
  • Añadieron etiquetas y marcadores correctos para los elementos de la interfaz, lo que simplificará significativamente el uso del servicio para personas usuarias con lectores de pantalla.

Como usamos Diplodoc para mostrar nuestra documentación, estas mejoras también aumentaron la accesibilidad de la documentación en el sitio de Yandex Cloud.

Resultados y planes

Dimos los primeros pasos para mejorar la accesibilidad de las interfaces de Yandex Cloud para todas las personas usuarias. Nos queda trasladar esta experiencia a otras interfaces del servicio y corregir los problemas que conocemos ahora.

Gravity UI facilitó nuestro trabajo de accesibilidad, y seguimos trabajando en los issues abiertos con la etiqueta a11y. En el momento de escribir el artículo tenemos 14 issues abiertos y 24 cerrados; podéis verlos aquí.

Full screen image

Esperamos vuestros PR y comentarios sobre accesibilidad y el funcionamiento de los servicios, así como ejemplos de uso de Gravity UI en vuestros sitios.

image

Vladimir Timoféyev
Gerente de proyectos técnicos en Yandex Cloud

Cómo hicimos Yandex Cloud más accesible con el sistema de diseño Gravity UI

Sign in to save this post