Développer un composant accessible pour afficher/masquer une zone

2 commentaires

Attention ! Cet article a été écrit en 2019. Son contenu a peut-être besoin d’une mise à jour. Complétez votre veille avec des articles plus récents, par exemple en consultant les nouveautés de notre blog accessibilité numérique, ou en lançant une recherche pour trouver des articles similaires, mais à jour.

Lorsque l’on a besoin de réduire des portions de contenus dans une page, notamment pour diminuer la charge informationnelle de contenus annexes, la solution la plus courante est d’utiliser une zone que l’utilisateur peut afficher ou masquer à volonté.

Nous détaillons dans cet article trois méthodes pour gérer ce système de zones affichées/masquées de manière accessible :

  • le changement d’intitulé de bouton ;
  • l’utilisation du motif de conception disclosure ;
  • l’utilisation de l’élément HTML details.

Nous vous proposons à la fin de l’article un mémo qui récapitule succinctement les conditions suffisantes à respecter pour choisir ou créer un tel composant accessible.

Technique 1 : modifier l’intitulé du bouton

Il s’agit de la technique la plus ancienne et la plus rudimentaire. L’implémentation consiste à simplement modifier l’intitulé du bouton « Afficher le contenu » par « Masquer le contenu ». Il s’agit d’informer textuellement l’utilisateur du changement d’état.

Vous trouverez dans notre page de test un exemple de code et de fonctionnement de cette technique.

L’élément qui gère l’affichage doit être un élément button ou implémenter le motif ARIA button.

<button type="button">Afficher la description</button>
<div class="is-closed">
<p>Le contenu est affiché et l'intitulé du bouton a changé !</p>
</div>

Bien que cette technique soit conforme au RGAA (Référentiel Général d’Accessibilité pour les Administrations), l’expérience utilisateur peut être améliorée (et standardisée) en utilisant le motif de conception ARIA disclosure.

Technique 2 : motif ARIA disclosure

Le motif de conception Disclosure décrit les propriétés ARIA et comportements claviers à implémenter pour gérer ce type de composants. À la différence de la première technique que nous venons de décrire, l’intitulé doit ici être neutre puisque l’état ouvert/fermé sera retranscrit par une propriété ARIA.

Vous trouverez dans notre page de test un exemple de code et de fonctionnement du motif ARIA disclosure.

Concernant les propriétés :

  • la zone possède un identifiant id unique (optionnel) ;
  • l’élément qui gère l’affichage est un élément button ou implémente le motif ARIA button ;
  • l’élément qui gère l’affichage possède la propriété aria-expanded :
    • dont la valeur est false lorsque la zone est masquée ;
    • dont la valeur est true lorsque la zone est affichée.
  • le bouton possède la propriété aria-controls qui référence la valeur de l’identifiant de la zone (optionnel) ;
<button aria-expanded="false" aria-controls="dd-infographie">Lire la transcription de la vidéo</button>
<div id="dd-infographie" class="is-closed">
[contenu]
</div>

Au clavier, les touches Entrée et Espace doivent permettre d’activer le bouton, c’est-à-dire successivement afficher et masquer le contenu.

Technique 3 : élément HTML natif details

L’élément HTML5 details permet de gérer automatiquement des zones affichées/masquées. Ce composant natif permet de délaisser toute la gestion des changements d’état (ouvert/fermé) au navigateur, ce qui réduit d’autant plus les erreurs d’implémentation.

Vous trouverez dans notre page de test un exemple de code et de fonctionnement de l’élément details.

Le composant est constitué de deux éléments :

  • le conteneur, élément details, qui contient le bouton, est le contenu à afficher/masquer ;
  • le bouton, élément summary.
<details>
<summary>dépliez moi</summary>
[contenu…]
</details>

details est fourni avec des goodies :

  • un attribut open est inséré sur la balise details lorsque le contenu est ouvert ;
  • details prend en charge l’événement JavaScript toggle ;
  • il est possible de styliser le chevron (et donc le supprimer) en ciblant le pseudo-élément ::after de l’élément summary.

Bien qu’il ne soit pas encore supporté par tous les navigateurs [1], l’élément details est très bien restitué dans les environnements où il est pris en charge (et donc avec la base de référence du RGAA 3) : sur Firefox et Chrome, avec NVDA ou JAWS, les interactions claviers sont conformes et les restitutions de l’état et du nom du bouton sont cohérentes (« bouton réduit », « bouton développé »).

Quant aux navigateurs qui ne le supportent pas (Internet Explorer et Edge), cela ne pose pas de problème d’accessibilité particulier puisque tout le contenu de l’élément est alors affiché, l’utilisateur accède donc à tout le contenu.

L’utilisation de details est donc une implémentation conforme au RGAA 3.

Enfin, la principale différence avec le motif disclosure est la construction du code source. En effet, avec details, le bouton (élément summary) et la zone masquée/affichée doivent être obligatoirement contenus dans un même élément (details). De plus, le bouton doit obligatoirement être situé avant la zone gérée, c’est-à-dire que summary est toujours le premier enfant de details.

En revanche, avec le motif ARIA disclosure, la construction du code est totalement libre à partir du moment où l’ordre de lecture et de tabulation est respecté.

Ordre de lecture cohérent

Quelle que soit l’implémentation choisie, il faut s’assurer que l’ordre dans lequel une personne ayant recours à une technologie d’assistance lit les contenus est cohérent, c’est-à-dire que lorsque le contenu masqué devient visible, la technologie d’assistance atteint la zone affichée immédiatement après le bouton.

Vous devez également vous assurer que l’ordre de tabulation est cohérent, c’est-à-dire que lorsque le contenu masqué devient visible, la tabulation suivante doit se faire sur le premier élément interactif (lien, bouton, vidéo, champ de formulaire, etc.) de la zone affichée.

Le meilleur moyen de garantir cette cohérence est de faire se succéder les deux éléments (le bouton et la zone) dans le code source.

<button type=”button”>[intitulé du bouton]</button>
<div class="content-to-toggle is-closed">
[contenu]
</div>

Cependant, si cela n’est pas possible, il est tout à fait envisageable que le bouton et la zone ne se succèdent pas dans le code, à condition que la reprise de focus soit gérée de manière cohérente par le script.

C’est d’ailleurs la fonction première de la propriété aria-controls : identifier la zone gérée par le bouton, notamment dans les cas où le lien entre le bouton et la zone ne peut être déduit de manière intuitive (par exemple lorsque la zone gérée n’est pas un nœud frère direct du bouton).

Dans le meilleur des mondes, lorsque l’attribut aria-controls est présent sur un élément, les technologies d’assistance devraient permettre aux utilisateurs d’accéder directement à la zone identifiée. C’est déjà le cas avec JAWS, qui annonce un raccourci clavier à activer pour atteindre cette zone. Mais à l’heure actuelle, c’est le seul lecteur d’écran à proposer cette fonctionnalité.

Le contenu masqué doit être vraiment masqué !

Sauf cas très particuliers de conception, lorsque le contenu est visuellement masqué, il ne doit être accessible ni aux utilisateurs ni aux technologies d’assistance. Autrement dit, on ne doit pas pouvoir atteindre le contenu masqué avec un lecteur d’écran ni avec la tabulation.

En effet, les zones affichées/masquées permettent d’alléger la page et de réduire la charge cognitive de l’utilisateur. Il faut donc que tous les utilisateurs, quelles que soient leurs technologies d’assistance éventuelles, puissent en bénéficier.

Masquer avec CSS

La méthode la plus robuste pour masquer un contenu est d’utiliser la propriété CSS display:none. Ainsi, le contenu est non seulement masqué visuellement, mais il est également rendu indisponible pour les technologies d’assistance.

Mais certaines interfaces ne peuvent pas utiliser cette méthode, par exemple lorsqu’il faut gérer des effets d’animations sur ces zones (effet d’agrandissement par exemple).

Dans ces cas, il est possible d’utiliser la propriété visibility:hidden qui rend le contenu inaccessible, mais permet les effets de transition.

Dans d’autres configurations de transitions encore plus complexes, il est également possible de jouer sur les propriétés CSS de dimensionnement (height ou width par exemple) pour afficher certaines zones. Sauf que, dans ce cas, le contenu reste accessible aux technologies d’assistance même s’il est masqué visuellement. Il faut donc accompagner le contenu de propriétés HTML pour qu’il soit ignoré par les technologies d’assistance.

Masquer avec HTML

Deux propriétés HTML peuvent être utilisées pour empêcher les technologies d’assistance de restituer les contenus masqués visuellement :

  • aria-hidden="true" sur la zone lorsqu’elle est masquée (lorsque la zone est affichée, on la passe à false ou on retire la propriété) ;
  • tabindex="-1" sur tous les éléments interactifs (liens, boutons, vidéos, etc.) de la zone lorsqu’elle est masquée (lorsque la zone est affichée, soit on supprime la propriété, soit on lui redonne sa valeur initiale) [2].

Cette implémentation est plus délicate, car le rétablissement des propriétés par défaut (notamment pour tabindex) peut vite devenir complexe à gérer et être source d’erreurs.

Mémo pour être conforme

Il y a 4 exigences pour choisir ou implémenter un composant de ce type de manière accessible et conforme au RGAA 3 :

  • le changement d’état peut être identifié :
    • par le changement d’intitulé (technique 1) ;
    • ou par la mise à jour de la propriété aria-expanded (technique 2) ;
  • l’élément qui gère la visibilité de la zone :
    • est un élément button,
    • ou implémente un motif ARIA button ;
  • la zone est rendue indisponible par l’une des méthodes suivantes :
    • par la définition de la propriété CSS display:none (ou visibility:hidden),
    • ou par l’ajout de la propriété aria-hidden="true" et la modification des valeurs de tabindex sur les éléments interactifs ;
  • l’ordre de lecture est cohérent :
    • l’élément qui gère la visibilité et la zone se succèdent dans le code source ;
    • ou le script gère manuellement des reprises de focus cohérentes et logiques.

Il vous est également possible d’utiliser directement l’élément details puisque nous avons vu qu’il est accessible avec les lecteurs d’écran et navigateurs de la base de référence, il n’est simplement pas supporté par Internet Explorer ni Edge.

Références documentaires

Tests RGAA 3 associés

Normes internationales

Notes

  • [1] L’élément details n’est pas supporté par Internet Explorer ni par Edge
  • [2] La valeur initiale de la propriété tabindex d’un élément interactif peut être : absence de la propriété (par exemple, par défaut, un lien balise <a> est focusable, mais ne possède pas de propriété tabindex), tabindex="-1", tabindex="0" ou encore tabindex="n",même si le recours à une valeur supérieure à 0 pour la propriété tabindex est fortement déconseillé. C’est là toute la complexité de cette méthode puisque le script doit être capable de gérer ces différents états possibles sur tous les éléments interactifs.

Publié le 19 février 2019 – Mis à jour le 09 janvier 2024

Catégorie : Développement

Tags : ARIA, HTML, JavaScript, RGAA, RGAA 3

À propos

  • Audrey Maniez

    Co-gérante et experte accessibilité numérique

    Audrey Maniez est experte senior en accessibilité numérique, formatrice, directrice pédagogique et co-gérante d’Access42. Grâce à une maîtrise poussée des différentes normes d’accessibilité numérique, Audrey réalise des audits d’accessibilité et accompagne nos clients dans leur démarche de mise en conformité aux normes en vigueur. Formatrice chevronnée, Audrey anime nos formations les plus techniques. Par ailleurs, elle a encadré la traduction officielle en français des WCAG 2.1 publiée par le W3C, et encadre en ce moment celle des WCAG 2.2.

2 commentaires

Développer un composant accessible pour afficher/masquer une zone
Bonjour et merci pour votre message,

L'intérêt d'utiliser la propriété aria-expanded est justement de ne pas toucher à l'intitulé du bouton. Maintenant, selon l'implémentation, il ne sera pas considéré comme non conforme d'avoir un intitulé changeant "afficher le contenu" / "masquer le contenu" ET la propriété aria-expanded.

L'utilisateur comprendra l'action du bouton, c'est juste que le message restitué par un lecteur d'écran pourra paraître un peu confus.

Par exemple, un bouton qui est déplié et donc le texte est modifié pour décrire l'action à venir, sera restitué : "masquer le contenu développé".

Pour le reste (button avec le role=button, aria-hidden avec visibiliyt:hidden) je n'ai pas de commentaires, il n'y a aucune contrainte à les cumuler.

En espérant avoir répondu à vos interrogations :-)

Développer un composant accessible pour afficher/masquer une zone
Bonjour, super article merci!

Je me pause une petite question, est ce une mauvaise pratique de cumuler les techniques ?
Par exemples :
- Changement d'intitulé cumulé avec la maj de aria-expanded
- Elément Button avec le role="button"
- Propriété CSS Visibility:hidden + aria-hidden="true"

Merci :-)

Les commentaires sont désormais fermés, mais vous pouvez toujours nous contacter pour réagir à cet article !