Best Practices

Accesibilidad en Angular

La web es utilizada por una amplia variedad de personas, incluidas aquellas que tienen deficiencias visuales o motoras. Existen diversas tecnologías de asistencia disponibles que facilitan mucho la interacción de estos grupos con aplicaciones de software basadas en la web. Además, diseñar una aplicación para que sea más accesible generalmente mejora la experiencia del usuario para todos los usuarios.

Para una introducción en profundidad sobre los problemas y técnicas para diseñar aplicaciones accesibles, consulta el curso Learn Accessibility de web.dev de Google.

Esta página aborda las mejores prácticas para diseñar aplicaciones Angular que funcionen bien para todos los usuarios, incluidos aquellos que dependen de tecnologías de asistencia.

Atributos de accesibilidad

Construir experiencias web accesibles a menudo implica establecer atributos de Aplicaciones de Internet Enriquecidas Accesibles (ARIA) para proporcionar significado semántico donde de otro modo podría faltar. Usa la sintaxis de plantilla de enlace de atributo para controlar los valores de los atributos relacionados con la accesibilidad.

Atributos y propiedades ARIA

Al enlazar a atributos ARIA en Angular, puedes usarlos directamente como cualquier otro atributo HTML.

<button [aria-label]="myActionLabel">…</button>

Los atributos ARIA estáticos funcionan como atributos HTML regulares.

<button aria-label="Save document">…</button>

CONSEJO: Por convención, los atributos HTML usan nombres en minúsculas (tabindex), mientras que las propiedades usan nombres en camelCase (tabIndex).

Algunos patrones ARIA exponen APIs DOM o entradas de directivas que aceptan valores estructurados (por ejemplo, colecciones de referencias de Element). Usa enlaces de propiedades estándar para esos casos para que la relación subyacente se mantenga sincronizada.

@Component({  template: `    <h2 #dialogTitle>Atención</h2>    <p #dialogDescription>Por favor revisa tus respuestas antes de continuar.</p>    <section      role="dialog"      [ariaLabelledByElements]="[dialogTitle, dialogDescription]">      <ng-content />    </section>`,})export class ReviewDialog {}

Aquí [ariaLabelledByElements] acepta un array de elementos, por lo que el enlace de propiedades mantiene las referencias de elementos actualizadas siempre que cambien los datos de la plantilla.

Consulta la guía de enlaces para un resumen de la sintaxis de atributos ARIA.

Componentes UI de Angular

La biblioteca Angular Material, que es mantenida por el equipo de Angular, es un conjunto de componentes UI reutilizables que busca ser completamente accesible. El Component Development Kit (CDK) incluye el paquete a11y que proporciona herramientas para soportar diversas áreas de accesibilidad. Por ejemplo:

  • LiveAnnouncer se usa para anunciar mensajes para usuarios de lectores de pantalla usando una región aria-live. Consulta la documentación de W3C para más información sobre regiones aria-live.

  • La directiva cdkTrapFocus atrapa el foco de la tecla Tab dentro de un elemento. Úsala para crear experiencias accesibles para componentes como diálogos modales, donde el foco debe estar restringido.

Para detalles completos de estas y otras herramientas, consulta la visión general de accesibilidad de Angular CDK.

Aumentando elementos nativos

Los elementos HTML nativos capturan varios patrones de interacción estándar que son importantes para la accesibilidad. Al crear componentes de Angular, debes reutilizar estos elementos nativos directamente cuando sea posible, en lugar de reimplementar comportamientos bien soportados.

Por ejemplo, en lugar de crear un elemento personalizado para una nueva variedad de botón, crea un componente que use un selector de atributo con un elemento <button> nativo. Esto se aplica más comúnmente a <button> y <a>, pero puede usarse con muchos otros tipos de elementos.

Puedes ver ejemplos de este patrón en Angular Material: MatButton, MatTabNav, y MatTable.

Usando contenedores para elementos nativos

A veces, usar el elemento nativo apropiado requiere un elemento contenedor. Por ejemplo, el elemento nativo <input> no puede tener hijos, por lo que cualquier componente personalizado de entrada de texto necesita envolver un <input> con elementos adicionales. Al simplemente incluir <input> en la plantilla de tu componente personalizado, es imposible para los usuarios de tu componente establecer propiedades y atributos arbitrarios al elemento <input>. En su lugar, crea un componente contenedor que use proyección de contenido para incluir el control nativo en la API del componente.

Puedes ver MatFormField como ejemplo de este patrón.

Caso de estudio: Construyendo una barra de progreso personalizada

El siguiente ejemplo muestra cómo hacer accesible una barra de progreso usando host binding para controlar atributos relacionados con la accesibilidad.

  • El componente define un elemento habilitado para accesibilidad con tanto el atributo HTML estándar role, como atributos ARIA. El atributo ARIA aria-valuenow está enlazado a la entrada del usuario.
  • En la plantilla, el atributo aria-label asegura que el control sea accesible para lectores de pantalla.

Enrutamiento

Gestión del foco después de la navegación

Rastrear y controlar el foco en una UI es una consideración importante al diseñar para accesibilidad. Al usar el enrutamiento de Angular, debes decidir dónde va el foco de la página al navegar.

Para evitar depender únicamente de señales visuales, necesitas asegurarte de que tu código de enrutamiento actualice el foco después de la navegación de la página. Usa el evento NavigationEnd del servicio Router para saber cuándo actualizar el foco.

El siguiente ejemplo muestra cómo encontrar y enfocar el encabezado de contenido principal en el DOM después de la navegación.

router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {  const mainHeader = document.querySelector('#main-content-header')  if (mainHeader) {    mainHeader.focus();  }});

En una aplicación real, el elemento que recibe el foco depende de la estructura y diseño específicos de tu aplicación. El elemento enfocado debe poner a los usuarios en una posición para moverse inmediatamente al contenido principal que acaba de ser enrutado a la vista. Debes evitar situaciones donde el foco regresa al elemento body después de un cambio de ruta.

Identificación de enlaces activos

Las clases CSS aplicadas a elementos RouterLink activos, como RouterLinkActive, proporcionan una señal visual para identificar el enlace activo. Desafortunadamente, una señal visual no ayuda a usuarios ciegos o con deficiencia visual. Aplicar el atributo aria-current al elemento puede ayudar a identificar el enlace activo. Para más información, consulta Mozilla Developer Network (MDN) aria-current).

La directiva RouterLinkActive proporciona la entrada ariaCurrentWhenActive que establece el aria-current a un valor especificado cuando el enlace se vuelve activo.

El siguiente ejemplo muestra cómo aplicar la clase active-page a los enlaces activos así como establecer su atributo aria-current a "page" cuando están activos:

<nav>  <a routerLink="home"      routerLinkActive="active-page"      ariaCurrentWhenActive="page">    Home  </a>  <a routerLink="about"      routerLinkActive="active-page"      ariaCurrentWhenActive="page">    About  </a>  <a routerLink="shop"      routerLinkActive="active-page"      ariaCurrentWhenActive="page">    Shop  </a></nav>

Carga diferida

Al usar los bloques @defer de Angular para la carga diferida de contenido, considera las implicaciones de accesibilidad para usuarios con tecnologías de asistencia. Los lectores de pantalla pueden no anunciar automáticamente los cambios de contenido cuando se cargan componentes diferidos, potencialmente dejando a los usuarios sin conocimiento del nuevo contenido.

Para asegurar que los cambios de contenido diferido se anuncien correctamente, envuelve tus bloques @defer en elementos con regiones ARIA live apropiadas. Para orientación detallada y ejemplos, consulta la sección de accesibilidad en la guía de defer.

Más información

Libros

  • "A Web for Everyone: Designing Accessible User Experiences," Sarah Horton and Whitney Quesenbery
  • "Inclusive Design Patterns," Heydon Pickering