lunes, 11 de diciembre de 2023

Accesibilidad en SPA (Single Page Application): 3 claves para garantizar una experiencia accesible e inclusiva.

Animación de cargando página

En muchos portales web no navegas realmente cuando pulsas los enlaces de las páginas, sino que todo el contenido de la página, o buena parte del mismo, se modifica dinámicamente. Es posible que ni siquiera te des cuenta... a menos que accedas con un lector de pantalla o solo con el teclado.

La experiencia de una persona ciega en una Single Page Application (SPA) en la que no se ha trabajado la accesibilidad puede ser desastrosa: escucha solo silencio cuando navega, no sabe dónde se encuentra y el foco de teclado se vuelve impredecible.

En este artículo voy a explicar cuáles son las 3 claves para que una Single Page Application (SPA) sea accesible para todas las personas.

Índice

Diferencia entre una Multiple Page Application (MPA) y una Single Page Application (SPA)

Una Multiple Page Application (MPA) y una Single Page Application (SPA) son dos enfoques diferentes para construir portales y aplicaciones web.

El enfoque tradicional y más habitual es el de una Multiple Page Application (MPA), donde cada página se carga por separado desde el servidor cuando el usuario solicita una nueva página. Es decir, cuando navegas de una página a otra, la aplicación realiza una solicitud al servidor para obtener la nueva página completa, de modo que la navegación implica recargar toda la página.

Por el contrario, en una Single Page Application (SPA):

  • Se carga una única página en el navegador del usuario.
  • A medida que interactúas con la aplicación, en lugar de cargar páginas completas desde el servidor, solo se cargan los datos necesarios y se actualiza dinámicamente la interfaz de usuario.
  • La transición entre secciones de la aplicación se realiza de manera suave sin recargar la página completa.
  • Se puede cambiar dinámicamente solo una parte del contenido, por ejemplo, la región principal, pero también en ocasiones todo el contenido de la página.

Por tanto, la principal diferencia radica en cómo se maneja la navegación y la carga de contenido.

En una MPA, cada página requiere una carga completa desde el servidor, mientras que en una SPA, la aplicación se carga una vez y la navegación subsiguiente ocurre de forma más rápida y fluida sin recargas completas de página.

Esquema comparativo entre el ciclo de vida de una página tradicional y una SPA. En una página tradicional se hacen peticiones al servidor y se recargan las páginas. En una SPA las páginas no se recargan, se modifican dinámicamente.

Imagen de Single-Page Applications: Build Modern, Responsive Web Apps with ASP.NET https://learn.microsoft.com/

En resumen, una MPA implica recargar páginas completas al navegar, mientras que una SPA carga la aplicación una vez y actualiza dinámicamente el contenido según las interacciones del usuario.

Un ejemplo tradicional de aplicación web SPA es Gmail, pero también lo son portales como Zara, Yoigo o Pinterest.

Feedback al usuario: incluye mensajes de cargado datos y de página cargada

Cuando accedes a un portal tradicional con un lector de pantalla, este te anuncia el título de la página que se ha cargado. Sin embargo, en una SPA solo hay silencio, porque realmente no se ha cargado la página, solo se ha modificado el contenido dinámicamente.

Para evitar este problema debemos trabajar con mensajes de estado.

Las WCAG no nos obligan a tener mensajes de estado, solo a marcarlos adecuadamente con ARIA para que sean anunciados por el lector de pantalla.

Si te limitas a cumplir estrictamente con las WCAG, las SPA podrían serán inaccesibles con el lector de pantalla. Necesitamos incluir obligatoriamente mensajes de estado.

Las buenas prácticas a seguir son:

  • Incluye un mensaje de estado cada vez que modifiques dinámicamente el contenido de la página. Lo más recomendable es que el mensaje esté visible para todas las personas.
  • Incluye atributos ARIA para que el lector de pantalla anuncie el mensaje aunque no tenga el foco:

    <div role="status" aria-live="polite"><p>Cargando datos de la página... <img alt="" src="spinner.gif"></p></div>

    Mesaje de cargando datos con una animación.

  • A menudo me encuentro que el mensaje de estado solo contiene la animación ... sin texto alternativo, de modo que el lector no tiene nada que anunciar. Si el mensaje es solo una animación, debe tener texto alternativo:

    <div role="status" aria-live="polite"><img alt="Cargando datos de la página..." src="spinner.gif"></div>

  • Igual de importante es anunciar que se están cargando los datos, como que la página ya se ha cargado. Cuando se carguen los datos modifica el mensaje de estado por "La página [título de la página] se ha cargado".

    <div role="status" aria-live="polite"><p>La página 'Proceso de compra. Paso 2 de 3 Dirección de envío' se ha cargado.</p></div>

  • El mensaje de que la página se ha cargado no suele estar visible para todas las personas, solo para las personas que acceden con un lector de pantalla. Recuerda que NO debes ocultar el mensaje con los estilos display:none o visibility:hidden, porque ocultan también el contenido para el lector de pantalla.

Artículos de interés:

Título de la página dinámico: proporciona a cada página un título único y descriptivo

En un portal tradicional MPA, cada página que se carga tiene su propio título de página (en la etiqueta <title> del <head>).

Sin embargo, en una SPA solo hay una página cuyo contenido se modifica dinámicamente, por tanto, aunque te parece que se cargan diferentes páginas, solo es una con su título inicial. Por ello, es imprescindible que se modifique dinámicamente el título de la página (el contenido de la etiqueta <title> del <head>).

Advertencia:

Cambiar dinámicamente el título de la página no provoca que el lector lo anuncie automáticamente como un mensaje de estado.

Por eso seguimos necesitando los mensajes de estado ya explicados.

Es raro encontrar una SPA de acceso público donde no se modifique dinámicamente el título, fundamentalmente por motivos SEO. Por la misma razón, es habitual encontrar errores cuando el título de la página no es relevante para el SEO: por ejemplo, podemos encontrar varias páginas de un proceso de compra que mantienen el mismo título; o que las páginas dentro de la zona de clientes, de acceso restringido, mantienen siempre el título de la página inicial.

El título de la página es importante para una persona usuaria de lector de pantalla, que puede preguntarlo en cualquier momento para ubicarse (normalmente con el atajo del lector: [tecla modificadora, como Insert] + "t").

Un título claro también es importante para cualquier persona: es el que se muestra en la pestaña del navegador, al guardar la página en marcadores, el nombre por defecto al compartir la página en redes sociales, etc.

Hay otra razón por la cuál el título puede ser relevante en una SPA. Ya he indicado que debemos incluir un mensaje de página cargada: "La página [título de la página] se ha cargado". Si utilizamos el contenido de la etiqueta <title> para generar dinámicamente el mensaje de página cargada, será muy confuso cuando el lector de pantalla anuncie que se han cargado diferentes páginas siempre con el mismo nombre:

Incorrecto: "La página 'Proceso de compra' se ha cargado", "La página 'Proceso de compra' se ha cargado", "La página 'Proceso de compra' se ha cargado" ...

Un título único y descriptivo para cada página provocará mensajes de estado más claros cuando se utiliza el título para generarlos:

Correcto: "La página 'Proceso de compra. Paso 1 de 3. Datos del cliente' se ha cargado", "La página 'Proceso de compra. Paso 2 de 3 Dirección de envío' se ha cargado", etc.

Control del foco de teclado

El tercer gran error que me suelo encontrar en las auditorías de portales o aplicaciones web SPA es el manejo del foco. Ten en cuenta que el usuario no sabe que se encuentra en una SPA ni tiene por qué saberlo.

Hay muchas personas que acceden a las páginas mediante pulsadores o solo con el teclado, entre ellas las personas que usan un lector de pantalla, muchas de las cuales son ciegas y no pueden ver dónde está el foco.

En un portal tradicional, cuando la página se carga, el foco de teclado se sitúa al comienzo de la página.

En una SPA donde no se ha trabajado la accesibilidad es muy confuso manejarte con el foco de teclado si no puedes ver la pantalla porque, a menudo, resulta impredecible saber a dónde irá el foco. Cuando se carga nuevo contenido, quizás el foco de teclado se pierda debido a la ausencia de un elemento que ya no está presente; o tal vez se quede donde está, aunque se haya anunciado la carga de una nueva página y tú esperes que el foco del teclado se encuentre ahora al inicio de la misma.

Por tanto, la tercera clave para que una SPA sea accesible es manejar correctamente el foco de teclado cuando el contenido se carga.

Para hacerlo bien impera el sentido común, conocer cómo acceden las personas usuarias de lector de pantalla y de teclado; e involucrarlas siempre que se pueda en las pruebas.

Opción 1. Mandar el foco de teclado al comienzo de la página

Si se está modificando dinámicamente todo el contenido central de la página, una opción puede ser mandar el foco al comienzo de la página, que es lo que el usuario espera. En concreto, sitúalo en el primer enlace del <body>: en el enlace "Saltar al contenido".

De este modo, después de que el mensaje de estado anuncie "La página [título de la página] se ha cargado", el foco se sitúa siempre de manera predecible al comienzo de la página, en el enlace para saltar al contenido central.

El usuario de lector de pantalla tiene el feedback necesario y es un comportamiento predecible.

El usuario de teclado que ve la página y no usa un producto de apoyo, no se queda con el foco en un lugar donde le resulte difícil regresar al inicio de la página o a la región principal. Por ejemplo, no se queda con el foco de teclado en el pie de página tras pulsar uno de sus enlaces.

Opción 2. Mandar el foco de teclado al título de la página

En otros casos, puede ser más usable mandar el foco al título de la página (al <h1> en el <main>).

Os pongo un ejemplo muy claro. Estas son dos pantallas de un curso accesible (de ejemplo) de isEazy, en concreto la página de inicio y una página interior:

Captura de la portada de un curso accesible de isEazy. En la cabecera está el botón de menú, el título del curso y el progreso. En el contenido está el título, una imagen y un botón Comenzar curso
Captura una página interior del curso del portal de la imagen anterior. Tiene la misma cabecera. Al final del contenido hay un botón Volver arriba y un botón Siguiente sección.

isEazy genera automáticamente la versión accesible de un curso como una SPA. Por tanto, cuando pulsas "Comenzar curso" o "Siguiente sección" no se navega a otra página, sino que se modifica dinámicamente el contenido de la página.

Teniendo en cuenta los elementos concretos de la cabecera del curso y que el objetivo del alumno es ir avanzando por los contenidos del mismo, la conclusión a la que llegamos en este proyecto fue que la mejor alternativa era enviar el foco al título de la página (al <h1> en el <main>). De este modo, el usuario avanza de manera rápida, fluida y consistente. También puedes simplificar el mensaje de cargando página a "La página se ha cargado" o "El contenido se ha cargado", puesto que a continuación coge el foco el título de la página (el <h1>), por lo que el lector ya lo va a anunciar y no es necesario repetirlo en el mensaje de estado.

Cuando envíes el foco de teclado a un elemento ten en cuenta estos dos puntos:

  • Si el elemento que coge el foco NO es un elemento de interacción, como en este caso el <h1>, debe tener el atributo tabindex="-1", nunca tabindex="0". Si le añades tabindex="0" cogerá el foco al tabular por la página. Si le añades tabindex="-1" solo cogerá el foco por programación, pero nunca al tabular por la página, que es lo correcto.
  • La indicación visual de que tiene el foco debe ser clara. Evita limitarte a un simple cambio de color; por ejemplo, podría estar resaltado mediante un recuadro.

Opción 3. Mantener el foco de teclado en el elemento de interacción pulsado

En otros casos, cuando se modifica dinámicamente solo una parte del contenido, mover el foco al comienzo de la página o al título no es la mejor solución.

Por ejemplo, puedes tener un buscador en la región principal, de modo que solo se recargan los resultados de la búsqueda:

Captura de una página del buscador de tiendas de Vodafone. El foco de teclado está en el botón Buscar tienda. Debajo se han recargado dinámicamente los resultados con un mensaje previo Mostrando 9 tiendas Vodafone

En este caso, puede ser más adecuado que:

  • el foco se quede en el botón "Buscar", como se muestra en el ejemplo anterior;
  • el mensaje "Mostrando 9 Tiendas" tenga los atributos ARIA de mensaje de estado que hemos comentado. De este modo, el lector de pantalla anunciará el mensaje aunque no se haya movido el foco. La siguiente tabulación nos llevará al primer resultado de la búsqueda.

Otras recomendaciones

Otras recomendaciones a tener en cuenta a la hora de plantear la accesibilidad de una SPA son:

  • Acuérdate de modificar la miga de pan convenientemente para que refleje en qué página estamos.
  • Si marcas el menú o paso actual, acuérdate de marcar el correcto cuando modifiques el contenido.
  • Tendrás que programar un retardo para que el lector de pantalla anuncie todo adecuadamente. Debemos asegurarnos de que el lector de pantalla carga el nuevo contenido en el búfer; y que le da tiempo a leer el mensaje de estado antes de leer el contenido que coge el foco, sin interrupciones ni cambios abruptos.

Si quieres añadir algún consejo más puedes proponerlo en los comentarios.

Esta no es la solución...

Una SPA puede suponer un grave problema de accesibilidad para las personas usuarias de lector de pantalla si no se trabaja correctamente la accesibilidad, pero si se siguen las pautas de accesibilidad que he dado, se genera una gran experiencia de usuario compatible con sus productos de apoyo.

Algunos portales tienen la tentación de solucionarlo incluyendo una overlay o widget de accesibilidad. En vez de hacer que su portal sea compatible con los productos de apoyo habituales de los usuarios, les obligan a usar un componente que incorporan en su portal y que no soluciona el problema.

Es como si al entrar a Aragón te obligáramos a bajarte de tu coche porque nuestras carreteras no están asfaltadas, pero hemos invertido unos millones de euros en comprar burros que ofrecemos a nuestros visitantes. Mejor invierte el dinero en asfaltar las carreteras.

Artículos relacionados:

0 comentarios :
Publicar un comentario