Compila apps de Angular más accesibles

b23a30a52c1169e4.png

La accesibilidad es un componente fundamental del desarrollo web, ya que garantiza que los usuarios puedan percibir, explorar y comprender las apps, además de interactuar con ellas. De hecho, 1 de cada 4 adultos de EE.UU. tiene una discapacidad que afecta sus principales actividades cotidianas. En todo el mundo, alrededor del 15% de la población (más de 1,000 millones de personas) tiene algún tipo de discapacidad, y del 2 al 4% experimenta dificultades significativas.

Algunas de las condiciones más comunes que afectan el uso de la Web de una persona son la ceguera o la visión reducida, la sordera o hipoacusia, las habilidades motoras restringidas, las discapacidades cognitivas y el daltonismo, entre muchas otras.

En este curso, usaremos a11y como abreviatura de accesibilidad. Esto se debe a que, en inglés, la palabra “accesibility” comienza con a, a la que siguen 11 caracteres y una y.

Si quieres obtener una introducción detallada a los problemas y técnicas para diseñar apps accesibles, consulta Accesibilidad.

Qué compilarás

  • Usarás las prácticas recomendadas y las técnicas integradas para abordar problemas comunes de accesibilidad web en una app de demostración de una tienda de bollitos asiáticos de Angular.
  • Cumplirás con todos los lineamientos de accesibilidad, WCAG 2.0 y ARIA 1.2, y aprobarás las auditorías de accesibilidad de axe y Lighthouse.

818cc91d17fae486.png 510ca511c265da81.png

Qué aprenderás

Conocerás ocho problemas comunes de accesibilidad en las apps de Angular que afectan a los usuarios, además de cómo identificarlos y solucionarlos. Específicamente, harás lo siguiente:

  • Usar las Herramientas para desarrolladores de Google Chrome, Lighthouse y axe con el fin de auditar la accesibilidad de tu app
  • Solucionar los inconvenientes de las apps de una sola página (SPA) con títulos únicos de páginas
  • Solucionar los problemas de contraste de color bajo para los usuarios con visión reducida
  • Usar código HTML semántico para garantizar que los lectores de pantalla naveguen correctamente por las páginas
  • Usar Angular Material y desanidar controles a fin de garantizar que los lectores de pantalla puedan acceder a todos los controles
  • Agregar compatibilidad con ARIA para lectores de pantalla
  • Importar y usar el paquete CDK a11y de Angular
  • Usar FocusTrap para la navegación en lectores de pantalla de componentes personalizados
  • Anunciar notificaciones con el CDK LiveAnnouncer
  • Detectar usuarios con el modo de contraste alto y, además, implementar temas con contraste alto

Requisitos

Obtén el código

Todo lo que necesitas para este proyecto se encuentra en un repositorio de GitHub. Para comenzar, clona el código y ábrelo en tu entorno de desarrollo favorito.

Clona el repositorio y publica la app

El método recomendado para completar este codelab es VSCode o un IDE local.

  1. Abre una nueva pestaña del navegador y ve a https://github.com/googlecodelabs/angular-accessibility.
  2. Bifurca y clona el repositorio y agrega cd angular-accessibility/ al repositorio.
  3. Revisa la rama del código de inicio git checkout get-started.
  4. Abre el código en VSCode o en el IDE que prefieras.
  5. Ejecuta npm install a fin de instalar las dependencias necesarias para ejecutar el servidor.
  6. Ejecuta ng serve para ejecutar el servidor.
  7. Abre una pestaña del navegador en http://localhost:4200.

¿Cuál es tu punto de partida?

Tu punto de partida es una app de restaurante básica diseñada para este codelab. El código se simplificó para demostrar los conceptos en este codelab y tiene poca funcionalidad.

93a2d45cdd58d830.png

Explora la demostración

Para comenzar, conoce las tres funciones de tu app:

  1. Usa la barra de navegación para ver las rutas Our Shop, Our Story y Find Us, y consulta los detalles de la empresa de bollitos asiáticos.
  2. Cambia los temas para activar o desactivar el modo claro y el oscuro.
  3. Personaliza el relleno, la cantidad y el color de los bollitos de tu pedido.
  4. Selecciona Purchase para registrar tu pedido personalizado en la consola.

Usa Angular para abordar problemas comunes de accesibilidad web

En este codelab, deberás enfocarte en la accesibilidad de las funciones existentes de la app. Primero, identificarás los problemas de a11y en ella y, luego, implementarás una solución para que el símbolo 🛑 cambie a ✅.

¿Cómo sabrás qué corregir?

Para comenzar cada ejemplo, reconoce el problema de accesibilidad mediante una combinación de pruebas manuales y automatizadas.

En el estado actual de la Web, es obligatorio realizar pruebas manuales de accesibilidad.

Existen herramientas que pueden identificar estos problemas, pero ninguna de ellas puede certificar que una app es totalmente accesible. Las pruebas manuales garantizan que pruebes una gran variedad de conceptos de a11y, como el orden de contenido lógico y la paridad de funciones.

Prueba manual

Para probar manualmente la accesibilidad en este curso, activa el lector de pantalla integrado de tu computadora y navega por la app con el teclado. Para obtener más información, consulta Semántica y lectores de pantalla.

Activa el lector de pantalla y navega por la pantalla para practicar.

Puedes usar VoiceOver integrado de macOS. Haz clic en Preferencias del sistema > Accesibilidad > VoiceOver > Activar VoiceOver. Para activar o desactivar VoiceOver, presiona rápidamente TouchID tres veces mientras mantienes presionada la tecla Command.

En este curso, verificarás los problemas de forma manual y usarás herramientas automáticas para verificar funciones automatizables específicas.

Prueba automatizada

También debes usar algunas herramientas de desarrollo a fin de automatizar y auditar tu app. Con ellas, puedes comprobar aspectos como la presencia de texto alternativo en una imagen o la proporción de contraste de un color de texto. Puedes considerar estas herramientas como linters, ya que pueden reconocer que hay texto alternativo, pero debes verificar manualmente que el contenido sea lógico y proporcione valor.

Herramientas para desarrolladores de Chrome y Lighthouse

  1. Abre las Herramientas para desarrolladores de Chrome.
  2. Selecciona la pestaña Lighthouse y selecciona la casilla de verificación Accessibility.
  3. Haz clic en Generate report para ejecutar una auditoría de a11y en Lighthouse.

3935811012517f4e.png

axe

  1. Instala la extensión de axe DevTools. Es posible que debas reiniciar el navegador para ver la extensión.
  2. Abre las Herramientas para desarrolladores de Chrome.
  3. Selecciona la pestaña axe DevTools y, luego, Scan all my page para ejecutar un análisis de axe DevTools.

7033f0ef4c1c3210.png

Análisis con lint

Puedes usar las reglas de ESLint en Angular a fin de verificar tu código para atributos de a11y automatizables.

En .eslintrc.json, agrega lo siguiente, que se aplica a la accesibilidad:

"@angular-eslint/template/accessibility-alt-text": 2,
"@angular-eslint/template/accessibility-elements-content": 2,
"@angular-eslint/template/accessibility-label-for": 2,
"@angular-eslint/template/no-positive-tabindex": 2,
"@angular-eslint/template/accessibility-table-scope": 2,
"@angular-eslint/template/accessibility-valid-aria": 2,
"@angular-eslint/template/click-events-have-key-events": 2,
"@angular-eslint/template/mouse-events-have-key-events": 2,
"@angular-eslint/template/no-autofocus": 2,
"@angular-eslint/template/no-distracting-elements": 2

Para obtener más información, consulta las reglas más recientes de ESLint en GitHub.

Tu punto de partida

Con los nuevos métodos de prueba, puedes identificar los siguientes problemas en tu app mediante las auditorías de Lighthouse y axe, y con VoiceOver manual:

1356f16f5505c9c9.png

Auditoría de accesibilidad:

  • 🛑 Todas las páginas tienen el mismo título.
  • 🛑 Los elementos deben tener suficiente contraste de color.
  • 🛑 El código HTML debe tener un orden, nombre y función lógicos.
  • 🛑 Los lectores de pantalla no pueden seleccionar las casillas de verificación anidadas.
  • 🛑 El lector de pantalla no lee los valores de los controles deslizantes.
  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Proporcionar títulos de página únicos y concisos ayuda a los usuarios que usan los servicios de a11y a comprender rápidamente el contenido y el propósito de una página web. Los títulos de página son fundamentales para los usuarios con discapacidad visual, ya que son el primer elemento de la página que anuncia el software de lectura de pantalla.

Angular es una app de una sola página y, por ello, la mayoría de las transiciones, como pasar a una página nueva, no implican volver a cargarla. Es decir, sin configuración adicional, cada página se lee con un título idéntico y no proporciona ningún valor para comprender su contenido o propósito.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 Todas las páginas tienen el mismo título.

Encontrarás estos pasos en los comentarios: TODO: #4. Define unique page titles.

Identifica el problema

Para identificar el problema, activa tu lector de pantalla y navega por las pestañas Our Shop, Our Story y Find Us para ver los títulos de las páginas:

  1. Activa VoiceOver.
  2. Usa la navegación por pestañas para avanzar entre las páginas.
  3. Verifica que el título de página siempre sea a11y en Angular.

Este problema se debe a que los títulos de las páginas deben ser únicos para que los usuarios comprendan rápidamente de qué se tratan sin tener que navegar por ellas.

cb92438126bb2be8.png

Agrega títulos significativos a la página

Si una página o vista cambia, debes administrar el título de la página como corresponda. Si quieres corregir este problema, utiliza el servicio Title de Angular a fin de definir títulos únicos para cada una de las páginas.

  1. Agrega un título único a cada una de las tres rutas definidas:

src/app/app-routing.module.ts

const routes: Routes = [
  { path: 'shop', component: ShopComponent, data: {title: 'Our Shop – a11y in Angular'} },
  { path: 'about', component: AboutComponent, data: {title: 'Our Story - a11y in Angular'} },
  { path: 'locate', component: LocationComponent, data: {title: 'Find Us - a11y in Angular'} },
  { path: '',   redirectTo: '/shop', pathMatch: 'full' },
  { path: '**', component: ShopComponent },
];
  1. Usa el servicio de Title para establecer el título de página según los datos de la ruta:

src/app/app.component.ts

import { Title } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map } from 'rxjs/operators';

export class AppComponent implements OnInit {
  title = 'a11y in Angular';

  constructor(private titleService: Title,
              private router: Router,
              private activatedRoute: ActivatedRoute) {}

  ngOnInit(): void {
    const appTitle = this.titleService.getTitle();
    this.router
      .events.pipe(
        filter(event => event instanceof NavigationEnd),
        map(() => {
          const child = this.activatedRoute.firstChild;
          if (child?.snapshot.data.title) {
            return child?.snapshot.data.title;
          }
          return appTitle;
        })
      ).subscribe((title: string) => {
        this.titleService.setTitle(title);
      });
  }
}

Verifica los cambios

Vuelve a activar el lector de pantalla y verifica los cambios. Ahora las páginas deberían tener títulos únicos.

5a85fdb689464137.png

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  • 🛑 Los elementos deben tener suficiente contraste de color.
  • 🛑 El código HTML debe tener un orden, nombre y función lógicos.
  • 🛑 Los lectores de pantalla no pueden seleccionar las casillas de verificación anidadas de frutas.
  • 🛑 El lector de pantalla no lee los valores de los controles deslizantes.
  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Tu diseño puede parecer genial, pero no sirve de nada si las personas con discapacidades visuales como el daltonismo no pueden leer tu contenido. Las Pautas de Accesibilidad al Contenido Web (WCAG 2.0) definen una serie de proporciones de contraste de colores, lo que garantiza que el contenido sea accesible para todos. En Angular y en la Web, puedes definir paletas de colores para garantizar que tus componentes cumplan con esos estándares y sean visibles para los usuarios con visión reducida y daltonismo.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 Los elementos deben tener suficiente contraste de color.

Encontrarás estos pasos en los comentarios: TODO: #5. Ensure adequate color contrast.

Usa las Herramientas para desarrolladores de Chrome a fin de identificar problemas de contraste bajo

Para identificar este problema, usa las Herramientas para desarrolladores de Chrome a fin de inspeccionar los elementos de tu app.

  1. Usa la herramienta de inspección para ver los botones del ícono de menú. Puedes ver que el contraste es 1.85, inferior a lo que indican los requisitos de las WCAG.

b2e27bca38a1649c.png

  1. Ejecuta la Auditoría de accesibilidad en Lighthouse o el análisis de axe para ver estos problemas de proporción de contraste.

c1cbc422fcdc89b.png

Cambia el color del tema de Material

El esquema de colores de tu componente se define en tu tema personalizado de Material. Debes actualizar el valor del tema para cumplir con los lineamientos de proporción de contraste y color.

Actualiza el tema de Material para usar un color de texto más oscuro y, así, aumentar la proporción de contraste de tus íconos:

src/styles.scss

$light-primary: mat.define-palette(mat.$pink-palette, $default: A100, $lighter: 100, $text: 900);

También puede usar las herramientas de accesibilidad integradas de las Herramientas para desarrolladores de Chrome a fin de encontrar colores que cumplan con los estándares, o bien actualizar valores de color específicos en Sass.

Verifica los cambios

Vuelve a inspeccionar los elementos y verifica los cambios. Ahora las páginas deberían tener títulos únicos.

a990337d9f3127fd.png

Auditoría de accesibilidad

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  • 🛑 El código HTML debe tener un orden, nombre y función lógicos.
  • 🛑 Los lectores de pantalla no pueden seleccionar las casillas de verificación anidadas de frutas.
  • 🛑 El lector de pantalla no lee los valores de los controles deslizantes.
  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Los elementos HTML nativos captan diversos patrones de interacción estándar que son importantes para la accesibilidad. Si bien se puede diseñar un párrafo como un intervalo y un div como un botón, los elementos HTML semánticos garantizan que los lectores de pantalla y la navegación del teclado comprendan las interacciones y los controles de tu código HTML.

Cuando crees componentes de Angular, debes reutilizar estos elementos nativos directamente cada vez que sea posible, en lugar de volver a implementar comportamientos compatibles. Esto garantizará que la página tenga una estructura de contenido y un flujo de contenido natural, y que la pestaña esté en un orden lógico para ayudar a los usuarios a navegar por el sitio web con un uso eficaz del teclado.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 El código HTML debe tener un orden, nombre y función lógicos.

Encontrarás estos pasos en los comentarios: TODO: #6. Use Semantic HTML.

Identifica el problema

  1. Activa VoiceOver.
  2. Use la navegación por pestañas para acceder a la pestaña Our Story.
  3. Observa que el orden de las pestañas no es secuencial.
  4. Haz clic en Purchase.
  5. Observa que el botón no se reconoce como tal.

69b5875f4d51d836.png

Cambia un elemento <div> a <button>

Reemplaza el elemento <div> personalizado por un botón de Material:

src/app/shop/shop.component.html

<button mat-flat-button
  color="primary"
  class="purchase-button"
  (click)="fauxPurchase()">
  Purchase
</button>

Usa elementos de encabezado en forma secuencial

Reordena el texto para usar HTML semántico y aplica un estilo con la tipografía de Angular Material:

src/app/about/about.component.html

<h2>Who are we?</h2>
<p class="mat-subheading-2">Have you ever thought, "wow, I love dumplings"?</p>
<p class="right mat-subheading-1">Who hasn't.</p>
<p class="center mat-subheading-1">We took it one step further and created Dumpling Dumpling,</p>
<p class="center mat-subheading-1">double the dumpling, double the fun.</p>
<div class="spacer"></div>
<h2>How are we different?</h2>
<p class="mat-subheading-2">Handmade in San Francisco, California, we craft fully customizable dumplings. Glitter? Rainbows? Vegan? We do it all.</p>
<p class="right mat-subheading-2">This shop is concept only.</p>

Verifica los cambios

Vuelve a activar el lector de pantalla y verifica los cambios. VoiceOver ahora reconoce el botón, y el texto se lee en un orden lógico.

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  •  El código HTML semántico garantiza una interacción lógica.
  • 🛑 Los lectores de pantalla no pueden seleccionar las casillas de verificación anidadas de tamaño.
  • 🛑 El lector de pantalla no lee los valores de los controles deslizantes.
  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Un patrón de interacción complicado para los servicios de accesibilidad es el de los controles anidados. Piensa en los elementos secundarios del menú o en las casillas de verificación anidadas. ¿Cómo le indicas a un usuario que puede seleccionar un subgrupo de opciones o navegar a un elemento de menú superior?

En Angular, puedes simplificar los menús y controles para crear componentes navegables reduciendo los controles tanto como sea posible. En este ejemplo, usarás el cuadro de lista de Angular Material para crear un ejemplo de patrón de interacción.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 Los lectores de pantalla no pueden seleccionar las casillas de verificación anidadas de tamaño.

Encontrarás estos pasos en los comentarios: TODO: #7. Create selectable controls with Angular Material.

Identifica el problema

Para identificar este problema, activaremos el lector de pantalla y, luego, intentaremos seleccionar una casilla de verificación anidada.

  1. Activa VoiceOver.
  2. Selecciona diferentes tipos de relleno.
  3. Observa que las casillas de verificación superiores no especifican casillas secundarias cuando se leen mediante VoiceOver. ¿Cómo puedes saber que no se anuló la selección de la casilla de verificación Vegan cuando se anuló la selección de la casilla Bok Choy?

885a9bd0dbbd842a.png

A11y en Angular Material

Deberás reemplazar la casilla de verificación semántica con la casilla de verificación de Angular Material, que contiene conocimientos integrados de este patrón de interacción. Es importante tener en cuenta que reemplazar los componentes con Material no garantiza la accesibilidad. Como cualquier otro componente, debes probarlo manualmente porque hay muchas formas de implementar la inaccesibilidad con Material.

Reemplaza casillas de verificación con casillas de verificación de Material

  1. Primero, agrega tu nueva lista de rellenos y una variable para almacenar los tipos de relleno seleccionados:

src/app/shop/shop.component.ts

@Component(...)
export class ShopComponent implements OnInit {
  fillings: string[] = ['Bok Choy & Chili Crunch', 'Tofu & Mushroom', 'Chicken & Ginger', 'Impossible Meat & Spinach'];
  selectedFillings: string[] = [];

  fauxPurchase(): void {
    let flavor = '';
    this.selectedFillings.forEach(filling => {
      flavor = flavor + " " + filling
    })
  }
}
  1. Agrega <mat-selection-list> para reemplazar esta agrupación desordenada de casillas de verificación HTML:

src/app/shop/shop.component.html

<mat-selection-list [(ngModel)]="selectedFillings"
  aria-label="Dumpling fillings">
  <mat-list-option *ngFor="let flavor of fillings"
    [value]="flavor"
    color="primary">
    {{ flavor }}
  </mat-list-option>
</mat-selection-list>

Tus comentarios de TODO también muestran las partes en las que puedes quitar algunos Sass no utilizados en src/app/shop/shop.component.scss a fin de limpiar el estilo.

Verifica los cambios

Vuelve a activar el lector de pantalla y verifica los cambios. Ahora tus casillas de verificación se pueden seleccionar y explorar de forma más intuitiva con un lector de pantalla.

e9d473e1e7949442.png

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  •  El código HTML semántico garantiza una interacción lógica.
  •  Todos los controles son accesibles para los lectores de pantalla.
  • 🛑 El lector de pantalla no lee los valores de los controles deslizantes.
  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Modificaste el código HTML semántico y los componentes de Material de la app de Angular, pero algunos componentes requieren que los lectores de pantalla naveguen por completo en atributos específicos.

La especificación de Aplicaciones de Internet de fácil acceso de la iniciativa de accesibilidad web (WAI-ARIA o ARIA) ayuda a abordar problemas que no pueden administrarse con HTML nativo. Te permite especificar atributos que modifican cómo se traduce un elemento al árbol de accesibilidad.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 El lector de pantalla no lee los valores de los controles deslizantes.

Encontrarás estos pasos en los comentarios: TODO: #8. Provide control labels with ARIA.

Identifica el problema

Para identificar este problema, activa el lector de pantalla y mueve el control deslizante:

  1. Activa VoiceOver.
  2. Navega al control deslizante de cantidad y cambia el valor.
  3. Observa que falta la etiqueta de valor.

2d7dd751d8f835e6.png

Usa atributos ARIA

Etiqueta el control con aria-label en <mat-slider>:

src/app/shop/shop.component.html

<mat-slider
  aria-label="Dumpling order quantity slider"
  id="quantity"
  name="quantity"
  color="primary"
  class="quantity-slider"
  [max]="13"
  [min]="1"
  [step]="1"
  [tickInterval]="1"
  thumbLabel
  [(ngModel)]="quantity">
</mat-slider>

Verifica los cambios

Vuelve a activar el lector de pantalla y verifica los cambios. Ahora puedes mover el control deslizante.

b21560426b30352c.png

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  •  El código HTML semántico garantiza una interacción lógica.
  •  Todos los controles son accesibles para los lectores de pantalla.
  •  El control deslizante utiliza atributos ARIA para proporcionar una etiqueta.
  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Hasta ahora, utilizaste las herramientas incorporadas de Angular para corregir los problemas comunes de a11y. Ahora, analicemos el módulo de a11y de CDK y cómo puede ayudarnos a resolver problemas más complejos y específicos de Angular.

Al final de esta sección, continuarás este curso con herramientas del módulo de a11y de Angular.

Encontrarás estos pasos en el comentario: TODO: #9. Add the power of @angular/cdk/a11y.

Importa el módulo

Agrega el módulo a tu app:

src/app/app.module.ts

import { A11yModule } from '@angular/cdk/a11y';

@NgModule({
  declarations: [...],
  imports: [
    A11yModule
  ],
  providers: [...],
  bootstrap: [...]
})

¿Qué hace '@angular/cdk/a11y' ?

El módulo de a11y proporciona varias herramientas para mejorar la accesibilidad y es particularmente útil para los autores de componentes.

En las secciones que aparecen más abajo, agregarás tres servicios comunes: FocusTrap, LiveAnnouncer y Contraste alto.

Para obtener más información sobre todos los demás servicios que proporciona @angular/cdk/a11y, consulta Accesibilidad.

Cuando un diálogo o modal está abierto, los usuarios interactúan solo dentro de él. Permitir que el enfoque escape fuera del diálogo combina contextos y crea un estado en el que el usuario no sabe en qué parte de la página se encuentra.

En Angular, la directiva cdkTrapFocus captura el enfoque de la tecla tab- dentro de un elemento. El objetivo de esta función es brindar una experiencia accesible para componentes como diálogos modales, en los que el enfoque debe ser limitado.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 El enfoque del lector de pantalla en el selector de color se sale del diálogo.

Encontrarás estos pasos en los comentarios: TODO: #10. Control focus with FocusTrap.

Identifica el problema

Para identificar este problema, activa el lector de pantalla y abre el diálogo selector de color.

  1. Activa VoiceOver.
  2. Usa la navegación por pestañas para cambiar el color.
  3. Observa el orden de enfoque intuitivo y la captura de enfoque en el selector de color.

2cad39ca0450a28e.png

Agrega FocusTrap

Puedes usar cdkFocusTrap para capturar y controlar el orden del enfoque en los componentes personalizados. Usar mat-dialog-content es suficiente para resolver la mayoría de los problemas de captura de enfoque en un diálogo. Agrega el atributo cdkFocusInitial para definir la región inicial del enfoque en el color del envoltorio del bollito asiático <mat-selection-list> dentro del diálogo del selector de color.

src/app/shop/color-picker/color-picker-dialog/color-picker-dialog.component.html

<mat-selection-list #colors aria-label="Dumpling wrapper color" multiple="false" cdkFocusInitial>
  ...
</mat-selection-list>

Verifica los cambios

Vuelve a activar el lector de pantalla y verifica los cambios. Ahora el enfoque está configurado inicialmente en Change Color en el diálogo.

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  •  El código HTML semántico garantiza una interacción lógica.
  •  Todos los controles son accesibles para los lectores de pantalla.
  •  El control deslizante utiliza atributos ARIA para proporcionar una etiqueta.
  •  El selector de color tiene una captura de enfoque correcta.
  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Los lectores de pantalla deben recibir una notificación cuando se produce algún cambio en la página. Imagina que intentas enviar un formulario o completar una compra y no te enteras de que se produjo un error que impide enviar el formulario. Es una situación frustrante.

LiveAnnouncer se usa para anunciar mensajes a los usuarios de lectores de pantalla que usan una región de aria-live a fin de garantizar que los lectores de pantalla reciban anuncios sobre las notificaciones y los cambios publicados en las páginas. Para obtener más información sobre las regiones de aria-live, consulta la WAI-ARIA de W3C. En Angular, llamar a LiveAnnouncer como servicio es una solución más fácil de probar que los atributos de aria-live.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 No se anuncian los cambios, los errores ni las notificaciones.

Encontrarás estos pasos en los comentarios: TODO: #11. Announce changes with LiveAnnouncer.

Identifica el problema

Para identificar este problema, activa el lector de pantalla y selecciona Purchase sin completar los campos del formulario:

  1. Activa VoiceOver.
  2. Usa la navegación por pestañas para cambiar el color y realizar una compra falsa.
  3. Observa que no hay indicación de qué color se seleccionó cuando sales del diálogo ni de que la compra no se lee.

8ec0de4079feaae7.png

Agrega LiveAnnouncer a tu código

Agrega LiveAnnouncer y anuncia la selección de colores y la compra falsa como una string. En una implementación real, esto puede leerse cuando navegas a un sistema de pago externo o si hay errores en el formulario.

  1. Agrega un anuncio cuando se seleccione un color:

src/app/shop/color-picker/color-picker-dialog/color-picker-dialog.component.ts

import { LiveAnnouncer } from '@angular/cdk/a11y';

@Component(...)
export class ColorPickerDialogComponent implements OnInit {
  constructor(
    public dialogRef: MatDialogRef<ColorPickerDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: ColorDialogData,
    private liveAnnouncer: LiveAnnouncer) { }

  public changeColor(color: string): void {
    this.liveAnnouncer.announce(`Select color: ${color}`);
    this.dialogRef.close();
  }
}
  1. Agrega un anuncio cuando se realice una compra falsa:

src/app/shop/shop.component.ts

import { LiveAnnouncer } from '@angular/cdk/a11y';

@Component(...)
export class ShopComponent implements OnInit {

  constructor(private liveAnnouncer: LiveAnnouncer) { }

  fauxPurchase(): void {
    let flavor = '...';
    const fakePurchase = `Purchase ${this.quantity} ${flavor}dumplings in the color ${this.color}!`;

    this.liveAnnouncer.announce(fakePurchase);
  }
}

Verifica los cambios

Vuelve a activar el lector de pantalla y verifica los cambios. Ahora recibes notificaciones de los errores.

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  •  El código HTML semántico garantiza una interacción lógica.
  •  Todos los controles son accesibles para los lectores de pantalla.
  •  El control deslizante utiliza atributos ARIA para proporcionar una etiqueta.
  •  El selector de color tiene una captura de enfoque correcta.
  •  Se anuncian los cambios, los errores y las notificaciones.
  • 🛑 No está habilitado el modo de contraste alto.

Microsoft Windows es compatible con una función de accesibilidad llamada modo de contraste alto. Este cambia el aspecto de todas las aplicaciones, incluidas las web, para aumentar drásticamente el contraste. En Angular, debes respetar las preferencias de los usuarios en tu app.

HighContrastModeDetector te permite determinar si el navegador se encuentra en un entorno con modo de contraste alto.

Internet Explorer, Microsoft Edge y Firefox son compatibles con este modo. Google Chrome no es compatible con el modo de contraste alto de Windows. Este servicio no detecta el modo de contraste alto cuando lo agrega la extensión Contraste alto del navegador Chrome.

Al final de esta sección, tu app pasará la siguiente auditoría:

  • 🛑 No está habilitado el modo de contraste alto.

Encontrarás estos pasos en los comentarios: TODO: #12. Enable HighContrast mode.

Identifica el problema

Para identificar este problema, abre tu app en Internet Explorer, Microsoft Edge o Firefox, activa el modo de contraste alto y observa que no hay cambios:

  1. Abre la app en Internet Explorer, Microsoft Edge o Firefox.
  2. Activa el modo de contraste alto.
  3. Observa que la aplicación no cambia.

Agrega compatibilidad con el modo de contraste alto

En styles.scss, usa el mixin cdk-high-contrast proporcionado en @angular/cdk/a11y para agregar un contorno a tus botones en el modo de contraste alto:

src/app/shop/shop.component.scss

@import '~@angular/cdk/a11y';

.purchase-button {
    border-radius: 5px;
    background-color: mat.get-color-from-palette(mat.$pink-palette, A100);

    @include cdk-high-contrast {
      outline: solid 1px;
      background-color: mat.get-color-from-palette(mat.$pink-palette, 50);
    }
}

:host-context(.dark-theme) {
  .purchase-button {
    background-color: mat.get-color-from-palette(mat.$light-green-palette, A100);

    @include cdk-high-contrast {
      outline: solid 1px;
      background-color: mat.get-color-from-palette(mat.$light-green-palette, 50);
    }
  }
}

Verifica los cambios

Actualiza la app y verifica los cambios. Agregaste un contorno al botón en el modo de contraste alto.

83c10ae8bd841e2e.png cb49574f76cdb85c.png

Auditoría de accesibilidad:

  •  Todas las páginas tienen títulos únicos.
  •  Los colores tienen una proporción de contraste suficiente.
  •  El código HTML semántico garantiza una interacción lógica.
  •  Todos los controles son accesibles para los lectores de pantalla.
  •  El control deslizante utiliza atributos ARIA para proporcionar una etiqueta.
  •  El selector de color tiene una captura de enfoque correcta.
  •  Se anuncian los cambios, los errores y las notificaciones.
  •  El modo de contraste alto está habilitado.

¡Felicitaciones! Resolviste problemas comunes de accesibilidad web en tu app de Angular 🎉.

Para ver todas las soluciones, revisa la rama main.

147ed8c9c57b3a2.png 2044559004149c85.png 4d594c26474fe97.png

Ahora conoces los pasos clave necesarios para resolver ocho dificultades comunes de a11y en tus aplicaciones de Angular.

Más información

Consulta estos codelabs:

Lee los siguientes materiales: