Criar apps Angular mais acessíveis

1. Antes de começar

bfaca8bec4a12c6e.png

A acessibilidade é uma parte essencial do desenvolvimento da Web, que garante que os usuários possam perceber, entender, navegar e interagir com os apps. Na verdade, um em cada quatro adultos dos EUA tem uma deficiência que afeta suas principais atividades de vida. No mundo todo, cerca de 15% da população mundial (mais de um bilhão de pessoas) tem algum tipo de deficiência. Por isso, cerca de 2 a 4% têm dificuldades significativas.

As condições mais comuns que afetam o uso da Web por uma pessoa incluem cegueira ou deficiências visuais, surdez ou deficiências auditivas, restrição de habilidades motoras, deficiências cognitivas e daltonismo. E essa é apenas uma lista parcial.

Neste curso, a11y é a forma abreviada de acessibilidade. Observe que a letra a é seguida por 11 caracteres e a letra y.

Para ver uma introdução detalhada sobre problemas e técnicas para desenvolver aplicativos acessíveis, consulte Acessibilidade.

O que você criará

  • Usar as práticas recomendadas e as técnicas integradas para resolver problemas comuns de acessibilidade na Web em um aplicativo de demonstração do Angular para uma loja de bolinhos
  • Atender a todas as diretrizes de acessibilidade, WCAG 2.0 e ARIA 1.2, além de conseguir a aprovação em auditorias de acessibilidade axe e Lighthouse.

ece6fe063441f552.png 6e401882e57c7878.png

O que você vai aprender

Você conhecerá oito problemas comuns de acessibilidade em aplicativos do Angular que afetam os usuários e verá como identificá-los e como corrigi-los. Mais especificamente, você fará o seguinte:

  • Usar as Ferramentas para desenvolvedores do Google Chrome, o Lighthouse e o axe para auditar a acessibilidade do seu aplicativo
  • Resolver desafios de aplicativos de página única (SPA, na sigla em inglês) com títulos de página exclusivos
  • Corrigir problemas de baixo contraste de cores para usuários com baixa visão
  • Usar HTML semântico para garantir que leitores de tela possam navegar pela página corretamente
  • Usar o Angular Material e desaninhar os controles para garantir que os leitores de tela acessem todos os controles
  • Adicionar compatibilidade com ARIA para leitores de tela
  • Importar e usar o pacote de acessibilidade do CDK do Angular
  • Usar o FocusTrap para navegação com leitor de tela usando componentes personalizados
  • Anunciar notificações com o CDK LiveAnnouncer
  • Detectar usuários com o modo de alto contraste e implementar temas de alto contraste

Pré-requisitos

2. Começar a configuração

Buscar o código

Tudo o que você precisa para este projeto está em um repositório do GitHub. Para começar, clone o código e abra-o no seu ambiente de desenvolvimento favorito.

Clonar o repositório e exibir o aplicativo

O VSCode ou um ambiente de desenvolvimento integrado local é o método recomendado para trabalhar com este codelab.

  1. Abra uma nova guia do navegador e acesse https://github.com/googlecodelabs/angular-accessibility.
  2. Ramifique e clone o repositório e use cd angular-accessibility/ no repositório.
  3. Confira a ramificação de código inicial git checkout get-started.
  4. Abra o código no VSCode ou no ambiente de desenvolvimento integrado de sua preferência.
  5. Execute npm install para instalar as dependências necessárias para executar o servidor.
  6. Execute ng serve para inicializar o servidor.
  7. Abra uma guia do navegador e acesse http://localhost:4200.

3. Definir um valor de referência

Qual é seu ponto de partida?

Seu ponto de partida é um aplicativo de restaurante básico desenvolvido para este codelab. O código foi simplificado para mostrar os conceitos deste codelab e tem poucas funcionalidades.

37c50b4b9a26e01e.png

Explorar a demonstração

Para começar, veja as três funcionalidades do seu aplicativo:

  1. Usar a barra de navegação para ver os títulos Nossa loja, Nossa história e Fale conosco e ver mais detalhes sobre a empresa de bolinhos.
  2. Trocar os temas para alternar entre o modo claro e escuro.
  3. Personalizar o recheio, a quantidade e a cor dos bolinhos no seu pedido.
  4. Selecionar Comprar para registrar seu pedido personalizado no console.

Usar o Angular para resolver problemas comuns de acessibilidade na Web

Neste codelab, você se concentrará na acessibilidade dos recursos existentes desse aplicativo. Comece identificando os problemas de acessibilidade no seu aplicativo e depois transforme 🛑 em ✅ implementando uma solução.

Como saber o que corrigir?

Inicie cada exemplo reconhecendo o problema de acessibilidade usando uma combinação de testes manuais e automáticos.

No estado atual da Web, é necessário testar a acessibilidade manualmente.

Você tem ferramentas que identificam problemas de acessibilidade, mas nenhuma delas pode confirmar que um aplicativo é totalmente acessível. O teste manual garante que você teste vários conceitos de acessibilidade que incluem ordem lógica de conteúdo e paridade de recursos.

Testes manuais

Para testar manualmente a acessibilidade neste curso, você precisa ativar o leitor de tela integrado do nosso computador e navegar pelo aplicativo com a navegação pelo teclado. Para mais informações, consulte Semântica e leitores de tela.

Para praticar, ative o leitor de tela e navegue pela tela.

Você pode usar o VoiceOver integrado do MacOS. Clique em Preferências do sistema > Acessibilidade > VoiceOver > Ativar o VoiceOver para ativá-lo. Para alternar o VoiceOver, pressione rapidamente o TouchID três vezes enquanto mantém a tecla Command pressionada.

Neste curso, você testará os problemas manualmente e usará ferramentas automatizadas para ajudar na verificação de recursos automatizáveis específicos.

Testes automatizados

Você também usará algumas ferramentas de desenvolvimento para automatizar e auditar seu aplicativo. Essas ferramentas permitem verificar itens como a presença de texto alternativo em uma imagem ou a taxa de contraste de uma cor de texto. Pense nessas ferramentas como lints: elas podem reconhecer que o texto alternativo está presente, mas é preciso verificar manualmente se o conteúdo é lógico e fornece valor.

Lighthouse e Ferramentas para desenvolvedores do Chrome

  1. Abra as Ferramentas para desenvolvedores do Chrome.
  2. Selecione a guia Lighthouse e marque a caixa de seleção Acessibilidade.
  3. Clique em Gerar relatório para gerar uma auditoria de acessibilidade do Lighthouse.

daeeff52d4e7c1ad.png

Axe

  1. Instale a extensão axe DevTools. Talvez seja necessário reiniciar o navegador para ver a extensão.
  2. Abra as Ferramentas para desenvolvedores do Chrome.
  3. Selecione a guia axe DevTools e a opção Verificar toda a página para realizar uma verificação do axe DevTools.

388bc5b5f6ffc050.png

Inspecionar

Você pode usar as regras ESLint do Angular para inspecionar o código em atributos de acessibilidade automatizáveis.

Em eslint.json, adicione o seguinte, que se aplica à acessibilidade:

"@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 saber mais, consulte as regras mais recentes no GitHub.

Seu ponto de partida

Com os novos métodos de teste, é possível identificar os seguintes problemas no seu app usando as auditorias do Lighthouse e axe, além do VoiceOver manual:

695dc88ffaada481.png

Auditoria de acessibilidade:

  • 🛑 Todas as páginas têm o mesmo título
  • 🛑 Os elementos precisam ter um contraste de cor adequado
  • 🛑 O HTML precisa ter ordem lógica, nome e função
  • 🛑 As caixas de seleção aninhadas não podem ser marcadas por leitores de tela
  • 🛑 O leitor de tela não lê os valores do controle deslizante
  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

4. Definir títulos de página exclusivos

Os títulos de página concisos e exclusivos ajudam os usuários que utilizam serviços de acessibilidade a compreender rapidamente o conteúdo e propósito de uma página da Web. Os títulos das páginas são fundamentais para os usuários com deficiência visual, porque são os primeiros elementos da página anunciados por um software de leitura de tela.

O Angular é um app de página única. Por isso, a maioria das transições, como a mudança para uma nova página, não envolve a atualização da página. Até recentemente, isso significava que cada página tinha um título idêntico e não oferecia valor para entender o conteúdo ou a finalidade dela.

No Angular v14, o Router adicionou um método integrado para definir títulos de página exclusivos prontos para uso. Isso proporciona uma abordagem simplificada para garantir que os desenvolvedores sigam as práticas recomendadas para títulos de página.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 Todas as páginas têm o mesmo título

Você pode encontrar cada uma das etapas abaixo do comentário: TODO: #4. Define unique page titles.

Identificar o problema

Para identificar esse problema, ative seu leitor de tela e navegue entre as guias Nossa loja, Nossa história e Fale conosco para ver os títulos das páginas:

  1. Ative o VoiceOver.
  2. Use a navegação por guias para navegar entre as páginas.
  3. Note que o título da página é sempre a11y no Angular.

Isso é um problema porque o título da página precisa ser exclusivo (link em inglês) para que o usuário entenda rapidamente o assunto sem precisar navegar por ela.

e516a6ed5c4329b1.png

Adicionar títulos de página significativos

Se uma página ou visualização mudar, é preciso gerenciar o título da página corretamente. Use a propriedade integrada Router.title (link em inglês) do Angular e defina títulos exclusivos para cada uma das suas páginas.

  1. Adicione um título exclusivo a cada uma das três rotas definidas:

src/app/app-routing.module.ts

const routes: Routes = [
  { path: 'shop', component: ShopComponent, title: 'Our Shop – a11y in Angular' },
  { path: 'about', component: AboutComponent, title: 'Our Story - a11y in Angular' },
  { path: 'locate', component: LocationComponent, title: 'Find Us - a11y in Angular' },
  { path: '',   redirectTo: '/shop', pathMatch: 'full' },
  { path: '**', component: ShopComponent },
];

Ela vai importar e usar automaticamente o Router's Title Service em segundo plano para que a mudança do título da página na navegação corresponda à propriedade de título definida em nossas rotas. Você também pode gerenciar títulos de página mais complicados usando uma TitleStrategy (links em inglês) personalizada.

Verificar mudanças

Ative o leitor de tela novamente e verifique as alterações. As páginas agora devem ter títulos exclusivos.

a2b4679fad1167f4.png

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • 🛑 Os elementos precisam ter um contraste de cor adequado
  • 🛑 O HTML precisa ter ordem lógica, nome e função
  • 🛑 As caixas de seleção aninhadas de frutas não podem ser marcadas por leitores de tela
  • 🛑 O leitor de tela não lê os valores do controle deslizante
  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

5. Garantir o contraste de cor adequado

Seu design pode até ser bonito, mas será inútil se as pessoas com deficiência visual, como daltonismo, não conseguirem ler o conteúdo. As Diretrizes de Acessibilidade para o Conteúdo da Web (WCAG 2.0, na sigla em inglês) definem uma série de taxas de contraste de cores, que garantem que o conteúdo seja acessível. No Angular e na Web, você pode definir paletas de cores para garantir que seus componentes atendam a esses padrões e que fiquem visíveis para os usuários com daltonismo e baixa visão.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 Os elementos precisam ter um contraste de cor adequado

Você pode encontrar cada uma das etapas abaixo nos comentários: TODO: #5. Ensure adequate color contrast.

Usar as Ferramentas para desenvolvedores do Chrome para identificar problemas de baixo contraste

Para identificar esse problema, use as Ferramentas para desenvolvedores do Google Chrome para inspecionar os elementos no seu aplicativo.

  1. Use a ferramenta de inspeção para ver os botões de ícones de menu. Observe que o contraste é 1,85 e está muito abaixo dos requisitos das WCAG (link em inglês).

2973d5cece93c888.png

  1. Execute a auditoria de acessibilidade na verificação do Lighthouse ou do axe para ver os problemas de proporção de contraste.

7bc061cf829384d0.png

Mudar a cor do tema do Material

O esquema de cores do seu componente é definido no seu tema do Material personalizado. Você atualiza o valor do tema para atender às diretrizes de taxa do contraste de cores.

Atualize o tema do Material para usar uma cor de texto mais escura, aumentando a taxa de contraste dos ícones:

src/styles.scss

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

Também é possível usar as ferramentas de acessibilidade integradas das Ferramentas para desenvolvedores do Google Chrome para encontrar uma cor que atenda aos padrões ou atualizar os valores de cores individuais no Sass.

Verificar mudanças

Inspecione seus elementos novamente e verifique as alterações. As páginas agora devem ter títulos exclusivos.

22f8a95026275e6b.png

Auditoria de acessibilidade

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • 🛑 O HTML precisa ter ordem lógica, nome e função
  • 🛑 As caixas de seleção aninhadas de frutas não podem ser marcadas por leitores de tela
  • 🛑 O leitor de tela não lê os valores do controle deslizante
  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

6. Usar um HTML semântico

Os elementos HTML nativos capturam vários padrões de interação que são importantes para a acessibilidade. Embora um parágrafo possa ser estilizado como um período e um div possa ser estilizado como um botão, o elemento HTML semântico garante que os leitores de tela e a navegação pelo teclado entendam as interações e os controles do HTML.

Ao criar componentes do Angular, é preciso reutilizar esses elementos nativos diretamente sempre que possível, em vez de implementar novamente os comportamentos mais compatíveis. Isso garante que a página tenha uma boa estrutura de conteúdo e um fluxo de conteúdo natural e que a guia esteja em uma ordem lógica para ajudar os usuários a navegar no site usando teclado de modo eficaz.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 O HTML precisa ter ordem lógica, nome e função

Você pode encontrar cada uma das etapas abaixo nos comentários: TODO: #6. Use Semantic HTML.

Identificar o problema

  1. Ative o VoiceOver.
  2. Use a navegação por guias para acessar a guia Nossa história.
  3. Observe que a ordem das guias não é sequencial.
  4. Clique em Comprar.
  5. Observe que o botão não é reconhecido como tal.

22874f81ab5a2fc.png

Mudar um <div> para um <button>

Substitua o <div> personalizado por um botão do Material.

src/app/shop/shop.component.html

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

Usar elementos de título sequencialmente

Reorganize o texto para usar HTML semântico e aplicar estilo usando a tipografia do 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>

Verificar mudanças

Ative o leitor de tela novamente e verifique as alterações. Agora o VoiceOver reconhece o botão e o texto é lido em uma ordem lógica.

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • O HTML semântico garante a interação lógica
  • 🛑 As caixas de seleção aninhadas de tamanho não podem ser marcadas por leitores de tela
  • 🛑 O leitor de tela não lê os valores do controle deslizante
  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

7. Criar controles selecionáveis com o Angular Material

Controles aninhados são um padrão de interação complicado para os serviços de acessibilidade. Pense em usar subitens de menu ou caixas de seleção aninhadas. Como indicar a um usuário que é possível selecionar um subgrupo de opções ou navegar para um item de menu pai?

No Angular, simplifique menus e controles para criar componentes navegáveis simplificando os controles o máximo possível. Neste exemplo, você usa a caixa de listagem do Material Angular para criar um exemplo desse padrão de interação.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 As caixas de seleção aninhadas de tamanho não podem ser marcadas por leitores de tela

Você pode encontrar cada uma das etapas abaixo nos comentários: TODO: #7. Create selectable controls with Angular Material.

Identificar o problema

Para identificar esse problema, ativaremos nosso leitor de tela e tentaremos marcar uma caixa de seleção aninhada.

  1. Ative o VoiceOver.
  2. Selecione diferentes sabores de recheio.
  3. Observe que as caixas de seleção pais não especificam filhos quando lidas pelo VoiceOver. Como você vai saber que a caixa de seleção Vegan foi desmarcada agora que desmarcou a caixa Bok Choy?

946a5a69a9939db7.png

Acessibilidade no Angular Material

Substitua a caixa de seleção semântica pela caixa de seleção do Angular Material, que contém conhecimento integrado sobre esse padrão de interação. A substituição de componentes pelo Material não garante a acessibilidade. Como qualquer outro componente, é preciso fazer o teste manualmente, porque há muitas maneiras de implementar o Material sem garantir a acessibilidade.

Substituir caixas de seleção comuns por caixas de seleção do Material

  1. Primeiro, adicione sua nova lista de recheios e uma variável para armazenar os sabores de recheio selecionados:

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. Adicione um <mat-selection-list> para substituir este agrupamento confuso de caixas de seleção 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>

Seus comentários do TODO também mostram onde é possível remover alguns Saas não usados em src/app/shop/shop.component.scss para limpar seu estilo.

Verificar mudanças

Ative o leitor de tela novamente e verifique as alterações. Agora, você pode usar um leitor de tela para selecionar e navegar de forma intuitiva por suas caixas de seleção.

f4a1fecca29acfa0.png

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • O HTML semântico garante a interação lógica
  • Todos os controles podem ser acessados por leitores de tela
  • 🛑 O leitor de tela não lê os valores do controle deslizante
  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

8. Fornecer identificadores de controle com ARIA

Você modificou os componentes do Material e de HTML semântico do seu app Angular, mas alguns deles exigem atributos específicos para serem totalmente utilizáveis por leitores de tela.

A especificação Web Accessibility Initiative's Accessible Rich Internet Applications (WAI-ARIA ou ARIA) ajuda a resolver problemas que não podem ser gerenciados com o HTML nativo. Ela permite especificar atributos que modificam o modo como um elemento é traduzido na árvore de acessibilidade.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 O leitor de tela não lê os valores do controle deslizante

Você pode encontrar cada uma das etapas abaixo nos comentários: TODO: #8. Provide control labels with ARIA.

Identificar o problema

Para identificar esse problema, ative o leitor de tela e mova o controle deslizante:

  1. Ative o VoiceOver.
  2. Navegue até o controle deslizante de quantidade e altere o valor.
  3. Observe que o identificador de valor está ausente.

7fa1790397652b35.png

Usar atributos ARIA

Controle de rótulo usando aria-label a <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>

Verificar mudanças

Ative o leitor de tela novamente e verifique as alterações. Agora, é possível mover o controle deslizante.

2c4b46d6394dd443.png

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • O HTML semântico garante a interação lógica
  • Todos os controles podem ser acessados por leitores de tela
  • O controle deslizante usa atributos ARIA para fornecer um rótulo
  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

9. Adicionar @angular/cdk/a11y

Até agora, você contava com ferramentas integradas do Angular para corrigir problemas comuns de acessibilidade. Agora, vamos dar uma olhada no módulo de acessibilidade do CDK e como ele pode nos ajudar a resolver problemas mais complicados e específicos do Angular.

Ao final desta seção, você continuará o curso com as ferramentas do módulo de acessibilidade do Angular.

Você pode encontrar essas etapas no comentário: TODO: #9. Add the power of @angular/cdk/a11y.

Importar o módulo

Adicione o módulo ao aplicativo:

src/app/app.module.ts

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

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

O que '@angular/cdk/a11y' faz?

O módulo de acessibilidade oferece diversas ferramentas para melhorar a acessibilidade e é especialmente útil para os autores dos componentes.

Nas seções a seguir, você adiciona três serviços comuns: FocusTrap, LiveAnnouncer e HighContrast.

Para mais informações sobre todos os outros serviços que @angular/cdk/a11y fornece, consulte Acessibilidade (link em inglês).

10. Controlar o foco com o FocusTrap

Quando uma caixa de diálogo ou modal é aberta, o usuário interage apenas dentro dela. Permitir que o foco escape para fora da caixa de diálogo mistura contextos e cria um estado em que o usuário não sabe onde está na página.

No Angular, a diretiva cdkTrapFocus captura o foco principal tab- em um elemento. Isso deve ser usado para criar uma experiência acessível em componentes como caixas de diálogo modal, em que o foco precisa ser restrito.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 Quando o foco do leitor de tela está no seletor de cores, a caixa de diálogo é fechada

Você pode encontrar essas etapas nos comentários: TODO: #10. Control focus with FocusTrap.

Identificar o problema

Para identificar esse problema, ative o leitor de tela e abra a caixa de diálogo do seletor de cores.

  1. Ative o VoiceOver.
  2. Use a navegação por guias para alterar a cor.
  3. Veja a ordem de foco intuitiva e a retenção de foco no seletor de cores.

2e2208ccfbe6ecdd.png

Adicionar o FocusTrap

cdkFocusTrap pode ser usado para interceptar e controlar a ordem de foco em componentes personalizados. Usar mat-dialog-content é o suficiente para resolver a maioria dos problemas ao reter o foco em uma caixa de diálogo. Adicione o atributo cdkFocusInitial para definir a região de foco inicial na cor do pacote de bolinho <mat-selection-list> na caixa de diálogo do seletor de cores.

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>

Verificar mudanças

Ative o leitor de tela novamente e verifique as alterações. Agora o foco é definido inicialmente em Alterar cor na caixa de diálogo.

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • O HTML semântico garante a interação lógica
  • Todos os controles podem ser acessados por leitores de tela
  • O controle deslizante usa atributos ARIA para fornecer um rótulo
  • O seletor de cores tem a retenção de foco correta
  • 🛑 Alterações, erros e notificações não são anunciados
  • 🛑 O modo de alto contraste não está ativado

11. Anunciar mudanças com o LiveAnnouncer

Os leitores de tela precisam ser notificados quando algo na página muda. Imagine que você está tentando enviar um formulário ou realizar uma compra sem saber que ocorreu um erro que impede o envio do formulário. Isso é frustrante!

O LiveAnnouncer é usado para anunciar mensagens para usuários de leitores de tela usando uma região aria-live para garantir que os leitores de tela sejam notificados sobre notificações e alterações na página ao vivo. Para mais informações sobre regiões aria-live, consulte a WAI-ARIA da W3C. No Angular, chamar o LiveAnnouncer como um serviço é uma solução mais fácil de testar do que os atributos aria-live.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 Alterações, erros e notificações não são anunciados

Você pode encontrar essas etapas nos comentários: TODO: #11. Announce changes with LiveAnnouncer.

Identificar o problema

Para identificar esse problema, ative o leitor de tela e selecione Comprar sem preencher os campos do formulário:

  1. Ative o VoiceOver.
  2. Use a navegação por guias para alterar a cor e fazer uma compra falsa.
  3. Observe que não há uma indicação de qual cor foi selecionada ao sair da caixa de diálogo, e a compra não é lida.

a04cab46d9634d07.png

Adicionar o LiveAnnouncer ao código

Adicione o LiveAnnouncer e anuncie a seleção de cores e a compra falsa como uma string. Em uma implementação real, isso pode ser lido quando você acessa um sistema de pagamento de terceiros ou em erros de formulário.

  1. Adicione um aviso quando uma cor for selecionada:

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. Adicione um aviso quando uma compra for feita:

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);
  }
}

Verificar mudanças

Ative o leitor de tela novamente e verifique as alterações. Agora você será notificado sobre os erros.

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • O HTML semântico garante a interação lógica
  • Todos os controles podem ser acessados por leitores de tela
  • O controle deslizante usa atributos ARIA para fornecer um rótulo
  • O seletor de cores tem a retenção de foco correta
  • Alterações, erros e notificações são anunciados
  • 🛑 O modo de alto contraste não está ativado

12. Ativar o modo de alto contraste

O Microsoft Windows tem suporte a um recurso de acessibilidade chamado de modo de alto contraste. Esse modo altera a aparência de todos os aplicativos, incluindo aplicativos da Web, para aumentar o contraste drasticamente. No Angular, você quer respeitar as preferências do usuário no aplicativo.

O HighContrastModeDetector permite que você determine se o navegador está em um ambiente com o modo de alto contraste ativo.

O Internet Explorer, o Microsoft Edge e o Firefox são compatíveis com esse modo. O Google Chrome não é compatível com o modo de alto contraste do Windows. Esse serviço não detecta o modo de alto contraste, conforme adicionado pela extensão de navegador de alto contraste do Chrome.

Ao final desta seção, seu app será aprovado na seguinte auditoria:

  • 🛑 O modo de alto contraste não está ativado

Você pode encontrar essas etapas nos comentários: TODO: #12. Enable HighContrast mode.

Identificar o problema

Para identificar esse problema, abra seu aplicativo no Internet Explorer, Microsoft Edge ou Firefox, ative o modo de alto contraste e observe a falta de alteração:

  1. Abra seu aplicativo no Internet Explorer, Microsoft Edge ou Firefox.
  2. Ative o modo de alto contraste.
  3. Observe que o aplicativo não foi alterado.

Adicionar compatibilidade com o modo de alto contraste

No styles.scss, use o mixin cdk-high-contrast fornecido em @angular/cdk/a11y para adicionar um contorno aos botões no modo de alto contraste:

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);
    }
  }
}

Verificar mudanças

Atualize o aplicativo e verifique as alterações. Você adicionou um contorno ao botão no modo de alto contraste.

41761f835ee4e373.png d07397a6e7de66fd.png

Auditoria de acessibilidade:

  • Todas as páginas têm títulos de página exclusivos
  • As cores têm uma taxa de contraste adequada
  • O HTML semântico garante a interação lógica
  • Todos os controles podem ser acessados por leitores de tela
  • O controle deslizante usa atributos ARIA para fornecer um rótulo
  • O seletor de cores tem a retenção de foco correta
  • Alterações, erros e notificações são anunciados
  • O modo de alto contraste está ativado

13. Parabéns!

Parabéns! Você resolveu problemas comuns de acessibilidade na Web do seu app Angular. 🎉

Para ver todas as soluções, confira a ramificação main.

b7f08de724e6887f.png 5257575d166e8cc3.png ecab44444063a53b.png

Agora você sabe as principais etapas necessárias para resolver oito armadilhas comuns de acessibilidade no seu app Angular.

Saiba mais

Confira estes codelabs:

Leia estes materiais: