Boas Práticas

Acessibilidade no Angular

A web é usada por uma grande variedade de pessoas, incluindo aquelas que têm deficiências visuais ou motoras. Uma variedade de tecnologias assistivas está disponível para facilitar muito a interação desses grupos com aplicações de software baseadas na web. Além disso, projetar uma aplicação para ser mais acessível geralmente melhora a experiência do usuário para todos.

Para uma introdução aprofundada sobre questões e técnicas para projetar aplicações acessíveis, veja o curso Learn Accessibility do web.dev do Google.

Esta página discute as melhores práticas para projetar aplicações Angular que funcionem bem para todos os usuários, incluindo aqueles que dependem de tecnologias assistivas.

Atributos de acessibilidade

Construir experiências web acessíveis frequentemente envolve configurar atributos Accessible Rich Internet Applications (ARIA) para fornecer significado semântico onde ele pode estar faltando. Use a sintaxe de template de binding de atributo para controlar os valores dos atributos relacionados à acessibilidade.

Ao fazer binding com atributos ARIA no Angular, você deve usar o prefixo attr.. A especificação ARIA depende especificamente de atributos HTML em vez de propriedades de elementos DOM.

<!-- Use attr. quando fizer binding com um atributo ARIA --><button [attr.aria-label]="myActionLabel">…</button>

NOTA: Esta sintaxe é necessária apenas para bindings de atributo. Atributos ARIA estáticos não requerem sintaxe extra.

<!-- Atributos ARIA estáticos não requerem sintaxe extra --><button aria-label="Save document">…</button>

DICA: Por convenção, atributos HTML usam nomes em minúsculas (tabindex), enquanto propriedades usam nomes camelCase (tabIndex).

Veja o guia de sintaxe de binding para mais informações sobre a diferença entre atributos e propriedades.

Components UI do Angular

A biblioteca Angular Material, que é mantida pela equipe Angular, é um conjunto de components UI reutilizáveis que visa ser totalmente acessível. O Component Development Kit (CDK) inclui o pacote a11y que fornece ferramentas para apoiar várias áreas de acessibilidade. Por exemplo:

  • LiveAnnouncer é usado para anunciar mensagens para usuários de leitores de tela usando uma região aria-live. Veja a documentação do W3C para mais informações sobre regiões aria-live.

  • A diretiva cdkTrapFocus captura o foco da tecla Tab dentro de um elemento. Use-a para criar experiências acessíveis para components como caixas de diálogo modais, onde o foco deve ser restrito.

Para detalhes completos dessas e outras ferramentas, veja a visão geral de acessibilidade do Angular CDK.

Aumentando elementos nativos

Elementos HTML nativos capturam vários padrões de interação padrão que são importantes para a acessibilidade. Ao criar components Angular, você deve reutilizar esses elementos nativos diretamente sempre que possível, em vez de reimplementar comportamentos bem suportados.

Por exemplo, em vez de criar um elemento personalizado para uma nova variedade de botão, crie um component que use um seletor de atributo com um elemento <button> nativo. Isso se aplica mais comumente a <button> e <a>, mas pode ser usado com muitos outros tipos de elementos.

Você pode ver exemplos deste padrão no Angular Material: MatButton, MatTabNav, e MatTable.

Usando containers para elementos nativos

Às vezes, usar o elemento nativo apropriado requer um elemento container. Por exemplo, o elemento <input> nativo não pode ter filhos, então quaisquer components de entrada de texto personalizados precisam envolver um <input> com elementos extras. Ao simplesmente incluir <input> no template do seu component personalizado, é impossível para os usuários do seu component definirem propriedades e atributos arbitrários para o elemento <input>. Em vez disso, crie um component container que use projeção de conteúdo para incluir o controle nativo na API do component.

Você pode ver MatFormField como um exemplo deste padrão.

Estudo de caso: Construindo uma barra de progresso personalizada

O exemplo a seguir mostra como tornar uma barra de progresso acessível usando host binding para controlar atributos relacionados à acessibilidade.

  • O component define um elemento habilitado para acessibilidade com o atributo HTML padrão role e atributos ARIA. O atributo ARIA aria-valuenow é vinculado à entrada do usuário.
  • No template, o atributo aria-label garante que o controle seja acessível para leitores de tela.
1import {Component, input} from '@angular/core';23/**4 * Example progressbar component.5 */6@Component({7  selector: 'app-example-progressbar',8  template: '<div class="bar" [style.width.%]="value()"></div>',9  styleUrls: ['./progress-bar.component.css'],10  host: {11    // Sets the role for this component to "progressbar"12    role: 'progressbar',1314    // Sets the minimum and maximum values for the progressbar role.15    'aria-valuemin': '0',16    'aria-valuemax': '100',1718    // Binding that updates the current value of the progressbar.19    '[attr.aria-valuenow]': 'value',20  },21})22export class ExampleProgressbarComponent {23  /** Current value of the progressbar. */24  value = input(0);25}2627
1<h1>Accessibility Example</h1>2<label for="progress-value">3  Enter an example progress value4  <input id="progress-value" type="number" min="0" max="100"5      [value]="progress" (input)="setProgress($event)">6</label>78<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->9<app-example-progressbar [value]="progress" aria-label="Example of a progress bar">10</app-example-progressbar>1112

Roteamento

Gerenciamento de foco após navegação

Rastrear e controlar o foco em uma UI é uma consideração importante ao projetar para acessibilidade. Ao usar roteamento do Angular, você deve decidir para onde o foco da página vai após a navegação.

Para evitar depender apenas de dicas visuais, você precisa garantir que seu código de roteamento atualize o foco após a navegação da página. Use o evento NavigationEnd do serviço Router para saber quando atualizar o foco.

O exemplo a seguir mostra como encontrar e focar o cabeçalho de conteúdo principal no DOM após a navegação.

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

Em uma aplicação real, o elemento que recebe o foco depende da estrutura e layout específicos da sua aplicação. O elemento focado deve colocar os usuários em uma posição para mover-se imediatamente para o conteúdo principal que acabou de ser roteado para a visualização. Você deve evitar situações em que o foco retorna ao elemento body após uma mudança de rota.

Classes CSS aplicadas a elementos RouterLink ativos, como RouterLinkActive, fornecem uma dica visual para identificar o link ativo. Infelizmente, uma dica visual não ajuda usuários cegos ou com deficiência visual. Aplicar o atributo aria-current ao elemento pode ajudar a identificar o link ativo. Para mais informações, veja Mozilla Developer Network (MDN) aria-current).

A diretiva RouterLinkActive fornece a entrada ariaCurrentWhenActive que define o aria-current para um valor especificado quando o link se torna ativo.

O exemplo a seguir mostra como aplicar a classe active-page a links ativos, bem como definir seu atributo aria-current para "page" quando eles estão ativos:

<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>

Deferred Loading

Ao usar blocos @defer do Angular para lazy loading de conteúdo, considere as implicações de acessibilidade para usuários com tecnologias assistivas. Leitores de tela podem não anunciar automaticamente mudanças de conteúdo quando components deferidos carregam, potencialmente deixando os usuários sem saber do novo conteúdo.

Para garantir que mudanças de conteúdo deferido sejam anunciadas adequadamente, envolva seus blocos @defer em elementos com regiões ARIA live apropriadas. Para orientação detalhada e exemplos, veja a seção de acessibilidade no guia defer.

Mais informações

Livros

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