Bonnes pratiques

Accessibilité dans Angular

Le Web est utilisé par une grande diversité de personnes, y compris celles qui ont des déficiences visuelles ou motrices. Diverses technologies d'assistance existent pour permettre à ces personnes d'interagir beaucoup plus facilement avec les applications web. Par ailleurs, concevoir une application plus accessible améliore généralement l'expérience utilisateur pour tous les utilisateurs.

Pour une introduction approfondie aux enjeux et aux techniques de conception d'applications accessibles, consultez le cours Learn Accessibility de web.dev, par Google.

Cette page présente les bonnes pratiques pour concevoir des applications Angular qui fonctionnent bien pour tous les utilisateurs, y compris ceux qui s'appuient sur des technologies d'assistance.

Attributs d'accessibilité

Créer des expériences web accessibles implique souvent de définir des attributs ARIA (Accessible Rich Internet Applications) pour apporter un sens sémantique là où il ferait autrement défaut. Utilisez la syntaxe de template de l'attribute binding pour contrôler les valeurs des attributs liés à l'accessibilité.

Attributs et propriétés ARIA

Pour un binding sur des attributs ARIA dans Angular, vous pouvez les utiliser directement comme n'importe quel autre attribut HTML.

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

Les attributs ARIA statiques fonctionnent comme des attributs HTML classiques.

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

Utile : Par convention, les attributs HTML utilisent des noms en minuscules (tabindex), tandis que les propriétés utilisent des noms en camelCase (tabIndex).

Certains patterns ARIA exposent des API DOM ou des inputs de directive qui acceptent des valeurs structurées (par exemple, des collections de références Element). Utilisez des property bindings classiques dans ces cas pour que la relation sous-jacente reste synchronisée.

@Component({
  template: `
    <h2 #dialogTitle>Attention</h2>
    <p #dialogDescription>Please review your answers before continuing.</p>

    <section role="dialog" [ariaLabelledByElements]="[dialogTitle, dialogDescription]">
      <ng-content />
    </section>
  `,
})
export class ReviewDialog {}

Ici, [ariaLabelledByElements] accepte un tableau d'éléments, donc le property binding maintient les références aux éléments à jour chaque fois que les données du template changent.

Consultez le guide des bindings pour un résumé de la syntaxe des attributs ARIA.

Composants d'interface Angular

La library Angular Material, maintenue par l'équipe Angular, est une suite de composants d'interface réutilisables qui vise une accessibilité complète. Le Component Development Kit (CDK) inclut le package a11y, qui fournit des outils couvrant divers aspects de l'accessibilité. Par exemple :

  • LiveAnnouncer sert à annoncer des messages aux utilisateurs de lecteurs d'écran via une région aria-live. Consultez la documentation du W3C pour en savoir plus sur les régions aria-live.

  • La directive cdkTrapFocus piège le focus de la touche Tab à l'intérieur d'un élément. Utilisez-la pour créer une expérience accessible pour des composants comme les boîtes de dialogue modales, où le focus doit être contraint.

Pour tous les détails sur ces outils et d'autres, consultez la présentation de l'accessibilité dans le CDK Angular.

Pour les composants au style personnalisé qui ont besoin de patterns d'interaction WAI-ARIA réutilisables, Angular Aria fournit des directives headless pour des patterns comme accordion, combobox, listbox, menu, tabs et toolbar. Ces directives gèrent l'interaction au clavier, les attributs ARIA, la gestion du focus et la prise en charge des lecteurs d'écran, tout en vous laissant fournir la structure HTML et le style de votre application.

Enrichir les éléments natifs

Les éléments HTML natifs intègrent plusieurs patterns d'interaction standard qui sont importants pour l'accessibilité. Lorsque vous écrivez des composants Angular, réutilisez directement ces éléments natifs quand c'est possible, plutôt que de réimplémenter des comportements déjà bien pris en charge.

Par exemple, au lieu de créer un custom element pour une nouvelle variété de bouton, créez un composant qui utilise un attribute selector avec un élément <button> natif. Cela s'applique le plus souvent à <button> et <a>, mais peut s'utiliser avec de nombreux autres types d'éléments.

Vous trouverez des exemples de ce pattern dans Angular Material : MatButton, MatTabNav et MatTable.

Utiliser des conteneurs pour les éléments natifs

Utiliser l'élément natif approprié nécessite parfois un élément conteneur. Par exemple, l'élément natif <input> ne peut pas avoir d'enfants, donc tout composant personnalisé de saisie de texte doit envelopper un <input> dans des éléments supplémentaires. Si vous vous contentez d'inclure <input> dans le template de votre composant personnalisé, les utilisateurs de votre composant ne peuvent pas définir de propriétés et d'attributs arbitraires sur l'élément <input>. Créez plutôt un composant conteneur qui utilise la projection de contenu pour inclure le contrôle natif dans l'API du composant.

Vous pouvez consulter MatFormField comme exemple de ce pattern.

Étude de cas : créer une barre de progression personnalisée

L'exemple suivant montre comment rendre une barre de progression accessible en utilisant le host binding pour contrôler les attributs liés à l'accessibilité.

  • Le composant définit un élément accessible avec à la fois l'attribut HTML standard role et des attributs ARIA. L'attribut ARIA aria-valuenow est lié à la saisie de l'utilisateur.
  • Dans le template, l'attribut aria-label garantit que le contrôle est accessible aux lecteurs d'écran.

Routing

Gestion du focus après la navigation

Suivre et contrôler le focus dans une interface est un point important de la conception accessible. Avec le routing Angular, vous devez décider où va le focus de la page lors de la navigation.

Pour ne pas dépendre uniquement d'indices visuels, assurez-vous que votre code de routing met à jour le focus après la navigation. Utilisez l'événement NavigationEnd du service Router pour savoir quand mettre à jour le focus.

L'exemple suivant montre comment trouver le titre du contenu principal dans le DOM et lui donner le focus après la navigation.

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

Dans une application réelle, l'élément qui reçoit le focus dépend de la structure et de la mise en page propres à votre application. L'élément qui reçoit le focus doit permettre aux utilisateurs d'accéder immédiatement au contenu principal qui vient d'être affiché par la navigation. Évitez les situations où le focus revient sur l'élément body après un changement de route.

Les classes CSS appliquées aux éléments RouterLink actifs, comme RouterLinkActive, fournissent un indice visuel pour identifier le lien actif. Malheureusement, un indice visuel n'aide pas les utilisateurs aveugles ou malvoyants. Appliquer l'attribut aria-current à l'élément peut aider à identifier le lien actif. Pour en savoir plus, consultez aria-current sur le Mozilla Developer Network (MDN)).

La directive RouterLinkActive fournit l'input ariaCurrentWhenActive, qui définit aria-current sur une valeur donnée quand le lien devient actif.

L'exemple suivant montre comment appliquer la classe active-page aux liens actifs et définir leur attribut aria-current sur "page" lorsqu'ils sont actifs :

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

Chargement différé

Lorsque vous utilisez les blocs @defer d'Angular pour le lazy loading de contenu, tenez compte des implications en matière d'accessibilité pour les utilisateurs de technologies d'assistance. Les lecteurs d'écran peuvent ne pas annoncer automatiquement les changements de contenu quand des composants différés se chargent, ce qui peut laisser les utilisateurs ignorer l'apparition de nouveau contenu.

Pour que les changements de contenu différé soient correctement annoncés, enveloppez vos blocs @defer dans des éléments dotés de régions ARIA live appropriées. Pour des conseils détaillés et des exemples, consultez la section sur l'accessibilité du guide de defer.

Pour en savoir plus

Livres

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