Reprise de focus et accessibilité

L’une des problématiques les plus complexes lorsqu’on développe des dispositifs JavaScript concerne la reprise de focus, c’est-à-dire le parcours de l’utilisateur avant, pendant et après le déclenchement d’une fonctionnalité.

Cet article a pour objectif d’expliquer les principes à appliquer, illustrés par quelques cas concrets.

Le parcours de tabulation

Un utilisateur doit pouvoir parcourir une page web ou une interface dans un ordre cohérent. Le parcours de la page ou de l’interface est concrétisé par le parcours du focus, lui-même lié à la tabulation.

La position du focus représente la position de l’utilisateur sur la page d’un site ou sur l’écran d’une application.

Dans le RGAA, c’est l’objet du critère 12.13 qui implémente le critère de succès WCAG 2.4.3 :

Critère 12.13 [A] : Dans chaque page web, l’ordre de tabulation est-il cohérent ?

Test 12.13.1 : Dans chaque page web, l’ordre de tabulation dans le contenu est-il cohérent ?

Test 12.13.2 : Pour chaque script qui met à jour ou insère un contenu, l’ordre de tabulation reste-t-il cohérent ?

Lorsque les contenus sont statiques, c’est l’ordre dans lequel ils sont implémentés dans le code HTML qui détermine le parcours séquentiel avec la touche de tabulation. En cas de problème, la réparation est relativement simple puisqu’il suffit de replacer les éléments concernés dans un ordre cohérent dans le code HTML et de gérer leurs positionnements visuels avec CSS.

L’enjeu est tout autre dès lors que l’on implémente des fonctionnalités complexes qui permettent d’enchaîner plusieurs actions sur une même page, d’injecter ou de mettre à jour des contenus dynamiques ou de recomposer la page en fonction d’une ou plusieurs actions de l’utilisateur. Les fonctionnalités qui permettent de téléverser plusieurs documents dans un formulaire en sont un exemple courant.

Quels sont les utilisateurs impactés ?

Les personnes ayant un handicap moteur et/ou un handicap visuel seront les plus impactées.

Il est important de comprendre que la perte de focus est malheureusement le quotidien de ces utilisateurs. En effet, cette problématique, qui peut être complexe, est généralement ignorée, ce qui peut rendre l’utilisation d’une application ou d’un site quasiment impossible, et ce même si les autres contenus ou fonctionnalités sont formidablement accessibles.

Comment gérer le focus de manière accessible ?

Le focus se gère avec la méthode JavaScript focus().

Si l’élément auquel vous transférez le focus est un élément interactif (bouton, lien, élément de formulaire, etc.), vous n’aurez rien d’autre à faire que d’appliquer cette méthode.

Si l’élément auquel vous transférez le focus n’est pas un élément interactif (titre, liste, texte, etc.), vous devrez utiliser l’une de ces deux méthodes :

  • Implémenter un tabindex="-1" pour définir la position courante du focus sans déplacer la tabulation. La prochaine tabulation prendra alors le focus sur le prochain élément capable de le recevoir après la position courante.
  • Implémenter un tabindex="0" pour définir la position courante du focus en déplaçant la tabulation.

Le choix de l’une ou l’autre de ces méthodes dépend du contexte d’utilisation et de votre propre choix quant au parcours que vous voulez proposer à votre utilisateur.

Mais où se trouve l’utilisateur ?

Il est donc essentiel de toujours se poser la question de savoir où se retrouve l’utilisateur après avoir lancé une fonctionnalité.

Pour illustrer ce principe, reprenons l’exemple d’un téléversement de fichier dans un formulaire et regardons quel est le parcours de l’utilisateur.

  1. Il clique sur le bouton lui permettant de téléverser un document ;
  2. Il quitte la page : une fenêtre s’ouvre pour lui permettre de sélectionner le fichier ;
  3. Il clique sur le bouton permettant de le téléverser ;
  4. Et ensuite… Il revient sur la page !

À l’issue de cette opération, lorsque l’utilisateur se retrouve de nouveau sur la page, où est-il ? Plusieurs hypothèses sont possibles. Il peut se retrouver :

  • Sur le nom du fichier téléversé ;
  • Sur le bouton permettant d’ajouter un nouveau fichier ;
  • Sur le bouton associé au fichier téléversé lui permettant de le supprimer ou de le modifier ;
  • À un emplacement incohérent avec l’action qu’il vient d’effectuer, par exemple en haut de page.

Reprise de focus

C’est ce qu’on appelle chez Access42 la « reprise de focus », dont la problématique centrale se résume à ceci :

Après chaque fonctionnalité qui affiche, masque, ajoute, supprime ou modifie un contenu dans la page, où doit-on repositionner le focus qui représente l’utilisateur ?

Modèle de conception ARIA

ARIA propose une série de modèles de composants riches, tels que les systèmes d’onglets, les mécanismes d’autocomplétion, les fenêtres modales, les datepickers, etc. sur lesquels la manipulation du focus est permanente.

Ces cas seront les plus simples à traiter puisque la gestion du focus est normée.

Par exemple, dans le cas d’une modale :

  1. Après l’ouverture, l’utilisateur doit se trouver dans la modale ;
  2. Tant que la modale est affichée, l’utilisateur doit être maintenu dans la modale ;
  3. À sa fermeture, l’utilisateur doit se trouver sur l’élément ayant permis de l’ouvrir.

Cette règle générale peut naturellement être adaptée. Par exemple, dans le cas d’un formulaire de connexion qui remplacerait le bouton « connexion » par un bouton « profil », ce serait sur le bouton « profil ».

Autres fonctionnalités

Si on ne dispose pas d’instructions prédéfinies, la situation va se complexifier assez rapidement puisqu’il va falloir imaginer un comportement cohérent avec la logique de la fonctionnalité.

Dans tous les cas, l’objectif est identique : il faut accompagner l’utilisateur et le déposer là où il est logique qu’il se trouve.

Voici quelques exemples qui pourraient vous inspirer dans vos développements.

Gestion des messages d’erreur

Commençons par un cas simple : la gestion des messages d’erreur dans les formulaires.

Lorsque l’utilisateur valide un formulaire, il est courant d’afficher les messages d’erreur sur la même page, sans rechargement de page.

Dans ce cas, la gestion de la reprise de focus est assez simple :

  1. L’utilisateur valide le formulaire ;
  2. Les messages d’erreur sont rendus visibles ou insérés dynamiquement ;
  3. L’utilisateur est repositionné sur le premier champ qui contient des erreurs ;
  4. Si un récapitulatif de toutes les erreurs est affiché avant le formulaire, il peut être plus logique de repositionner l’utilisateur sur cette zone.

Variante : message de confirmation d’envoi

Un autre cas fréquent consiste à afficher un message de confirmation lorsque le formulaire a bien été envoyé.

Dans ce cas, vous pouvez utiliser deux méthodes :

  • La première consiste à repositionner l’utilisateur sur le message de confirmation, par exemple dans le cas où il paraît logique qu’il puisse continuer la visite dans la page.
  • La seconde, s’il ne paraît pas logique que l’utilisateur continue à visiter la page, implémenter un role="alert" [1] sur le message de confirmation et repositionnez l’utilisateur en haut de page pour qu’il puisse atteindre rapidement le menu de navigation par exemple.

Carrousel, mon amour

Exemple d'un carrousel
Exemple d’un carrousel

Source de l’image : site doisjeutiliser.fr

Les carrousels sont un excellent exemple des difficultés que l’on peut avoir à gérer les reprises de focus et, en l’occurrence, à choisir la bonne méthode et à privilégier une logique plutôt qu’une autre.

Plusieurs éléments sont en jeu dans un carrousel :

  • Les contrôles qui permettent d’afficher les contenus de manière séquentielle (suivant/précédent) ;
  • Les contrôles qui permettent de stopper ou lancer le défilement automatique (lecture/pause) ;
  • Les contrôles qui permettent d’afficher chacune des « diapos » (barre de navigation) ;
  • Les contenus des diapos elles-mêmes s’ils contiennent des éléments interactifs comme des liens.

Jusqu’à assez récemment, on ne disposait pas d’un modèle de conception ARIA et c’était la foire d’empoigne.

Globalement, on pouvait classer les carrousels dans trois catégories, en terme de navigation :

  • Bouton de contrôle de lecture > bouton précédent > contenu > bouton suivant > barre de navigation ;
  • Bouton précédent > bouton suivant > contenu > bouton de contrôle de la lecture > barre de navigation ;
  • Contenu > bouton précédent > bouton suivant > bouton de contrôle de la lecture > barre de navigation.

Ces différents scénarios rendaient leur utilisation particulièrement complexe puisque l’utilisateur était confronté à des composants qui ne fonctionnaient jamais de la même manière.

Quelle que soit la formule choisie, la grande question restait de savoir quoi faire après que l’utilisateur ait activé l’un des boutons de la barre de navigation : fallait-il déplacer le focus sur le contenu affiché ou au contraire le laisser sur le bouton ?

Cette problématique est très caractéristique des difficultés liées à la reprise de focus. En effet, aucune de ces deux solutions n’était réellement satisfaisante : dans les deux cas, la reprise de focus allait générer des parcours complexes et de nombreux aller-retours entre les contenus affichés et la barre de navigation.

Depuis la publication des modèles de conception ARIA 1.1, le carrousel dispose enfin d’un modèle de conception [2] qui fait intervenir le comportement d’un tabpanel pour gérer ce problème de gestion du focus entre la barre de navigation et le contenu affiché.

Autrement dit dans cette configuration, ce n’est plus la tabulation qui permet d’afficher un contenu à partir de la barre de navigation, mais les flèches de direction. Cela ne résout que très partiellement les difficultés pour un utilisateur aveugle ou qui ne peut pas utiliser la souris, mais cela permet d’harmoniser le comportement.

Fonctionnalités associées à une liste

Sur le web, on peut croiser des listes d’éléments, dans lesquelles chaque élément est associé à une ou plusieurs fonctions précises (édition et suppression par exemple).

L’exemple ci-dessous présente un tableau contenant la référence, le titre et le format de cinq documents. Chaque document est associé à des fonctionnalités d’édition et de suppression. Le tableau est précédé d’une fonctionnalité permettant d’ajouter un document au tableau.

Cet exemple est intéressant car il cumule plusieurs cas habituels de gestion de la reprise de focus, comme le téléversement de fichier dans un formulaire.

Fonctionnalité de suppression

Lorsque l’utilisateur active la fonctionnalité de suppression, après la suppression il devra être repositionné selon la logique complexe suivante :

  • Si l’action de suppression concerne le dernier objet de la liste, déplacer le focus sur le bouton de suppression précédent s’il existe ;
  • Dans tous les autres cas (la fonctionnalité concerne le premier objet ou un objet quelconque de la liste), déplacer le focus sur le bouton de suppression suivant ;
  • S’il n’y a qu’un objet dans la liste, déplacer le focus sur un élément cohérent. Dans l’exemple ci-dessus, ce serait le bouton permettant d’ajouter un document à la liste.

Attention toutefois, cette proposition n’est qu’un exemple de traitement logique, il peut y avoir d’autres manières de gérer cette fonctionnalité, dictées notamment par des logiques métiers.

Il pourrait être tout aussi pertinent de déplacer le focus non pas sur les boutons des fonctionnalités d’édition ou de suppression, mais sur la première cellule de chaque ligne.

Néanmoins, le fait de repositionner l’utilisateur sur les boutons peut lui permettre de réaliser des traitements en séquences, ce qui peut être très pratique.

Fonctionnalité d’édition

La fonctionnalité permettant d’éditer le document sera probablement plus complexe à traiter. Tout dépend de la manière dont cette fonctionnalité est gérée : affichage d’une fenêtre modale ou d’une zone d’édition quelque part dans la page ou encore affichage d’une autre page.

Dans le cas où l’action se déroule dans la même page, le comportement devra être identique à celui de la fonction de suppression.

Fonctionnalité d’ajout de document

Concernant la fonctionnalité d’ajout d’un document au tableau, la reprise de focus va dépendre de la manière dont l’utilisateur est prévenu que le document a été ajouté.

  • S’il est prévenu par un message explicite [3], autant le laisser sur le bouton lui permettant d’ajouter un autre document pour favoriser les actions en séquences ;
  • Sinon, il vaut mieux le repositionner sur la première cellule de la ligne créée pour ajouter le document, ou sur le bouton « Supprimer » de cette même ligne si l’on veut favoriser l’annulation de l’action.

Moteur de recherche dynamique

Les moteurs de recherche dynamiques sont un autre exemple de dispositifs nécessitant une gestion de la reprise de focus minutieuse.

On voit de plus en plus la mise en ligne de moteurs de recherche qui affichent des résultats sans rechargement de page.

Ils sont de deux types :

  • Les moteurs qui affichent les résultats après une action sur le bouton « rechercher » (premier cas) ;
  • Les moteurs qui affichent les résultats de manière dynamique (autocomplétion) au fur et à mesure de la saisie de l’utilisateur (second cas).

Note sur la zone mise à jour

En préambule, ne déclarez jamais, mais vraiment jamais, la zone d’affichage en aria-live [4]. Cela déclenche la vocalisation de la zone à chaque mise à jour, ce qui est particulièrement inapproprié sur de gros volumes de texte.

Note sur la présence d’un bouton d’action pour le second type de moteur de recherche

Dans le cas de l’utilisation d’un moteur de recherche dynamique en autocomplétion, le bouton de recherche paraît superflu. Il est pourtant nécessaire d’implémenter un bouton de soumission pour faire face à toutes les situations possibles. Dans les exemples ci-dessous, on suppose que ce bouton existe.

Premier cas

Ce premier cas est simple à traiter :

  1. L’utilisateur saisit le terme recherché et clique sur le bouton ;
  2. La zone de résultats se met à jour et les résultats s’affichent ;
  3. L’utilisateur est repositionné au début de la zone mise à jour.

Le traitement décrit ci-dessus va être utilisé dans la plupart des autres cas avec quelques variantes.

Second cas

Le second cas peut se subdiviser en deux scénarios avec la même solution.

Premier scénario, il n’y a pas de message permettant de connaître le nombre de résultats

La reprise de focus va être identique au premier cas :

  1. L’utilisateur saisit le terme recherché : la zone de résultats est mise à jour dynamiquement ;
  2. L’utilisateur qui en a besoin clique sur le bouton ;
  3. L’utilisateur est repositionné au début de la zone mise à jour.
Second scénario, il existe un message d’information sur le nombre de résultats

L’affichage du nombre de résultats enrichi le processus car l’utilisateur peut confirmer sa recherche en allant consulter les résultats ou, à l’inverse, la modifier en fonction du nombre de résultats trouvés.

Pour que cela fonctionne, il faudra déclarer la zone de texte affichant le nombre de résultats avec la propriété aria-live.

  1. L’utilisateur saisit le terme recherché : la zone de résultats est mise à jour dynamiquement ;
  2. L’utilisateur est informé du nombre de résultats il peut ainsi confirmer ou modifier sa recherche ;
  3. L’utilisateur clique sur le bouton « rechercher » qui pourrait avoir comme meilleur nom : « Voir les résultats » pour être cohérent avec l’annonce dynamique du nombre de résultats ;
  4. L’utilisateur est repositionné au début de la zone mise à jour.

Moteur de recherche associé à des filtres

C’est ici que les choses peuvent se compliquer car la solution à adopter va dépendre de la nature et du fonctionnement des filtres associés au moteur de recherche.

Dans cet exemple, la zone de résultats est précédée d’une fonctionnalité de tri, d’un champ de sélection de thèmes et d’un champ de saisie de mots clés de recherche.

Fonctionnalité de tri et sélection des thèmes

Premier cas, options de recherche

Les deux fonctionnalités agissent comme des options de recherche, elles sont actives avant que l’utilisateur effectue sa recherche.

Dans ce cas, il n’y a rien à faire, l’ordre naturel d’implémentation est suffisant car aucune action n’est déclenchée à la sélection des options de tri ou de filtre.

Second cas, fonctionnalités de filtres de recherche

Les deux fonctionnalités agissent comme des filtres, elles ne sont actives que lorsque les résultats sont affichés.

Le principe de reprise de focus peut être le suivant :

  1. L’utilisateur sélectionne une option de tri ou sélectionne un thème ;
  2. L’utilisateur valide son option en appuyant sur entrée ;
  3. L’utilisateur est repositionné au début de la liste de résultats.

Mais plusieurs questions peuvent alors se poser :

Ordre des éléments

Puisque les fonctionnalités ne sont actives que lorsque les résultats sont affichés, il peut paraître plus logique qu’elles soient positionnées après le champ de recherche.

Dans ce cas, se pose un problème sur le déclenchement de la recherche : si on déplace le focus sur la zone de résultats après le déclenchement du bouton « rechercher », la zone de tri risque d’être ignorée par les utilisateurs aveugles par exemple.

Il peut alors être nécessaire de ne pas déplacer le focus sur la zone de résultats mais sur la première option de tri afin de l’informer de la possibilité de trier les résultats.

Déclenchement des options de filtre

S’il y a beaucoup de fonctionnalités de tri ou de filtre, la méthode proposée va obliger l’utilisateur, s’il veut cumuler les options, à des allers-retours entre la zone d’affichage des résultats et la zone de tri.

Dans ce cas, il sera plus intéressant d’ajouter un bouton « trier les résultats » après la zone de tri pour lui permettre de cumuler les filtres et d’attendre qu’il déclenche les actions de tri et de filtrage pour déplacer le focus sur la zone de résultats.

D’ailleurs, certains experts peuvent légitimement considérer que la présence de ce bouton est très importante même s’il n’y a qu’une option de tri.

Comportements cumulés

Il est possible que ce genre de fonctionnalité adopte les deux comportements : à la fois, trier la liste des résultats et servir d’option de recherche.

Dans ce cas, nous avons une difficulté, car savoir quand opter pour un transfert de focus sur la zone de résultat (utilisation de filtre) et laisser le focus sur le champ sélectionné (option de recherche) n’est pas possible.

Il n’existe pas de réponse véritablement pratique, tout dépend du comportement global du dispositif, de la logique métier ou du comportement qui va nous sembler le plus approprié.

En revanche, il est très probable que le choix de laisser le focus sur le champ sélectionné, donc d’adopter le comportement d’option de recherche par défaut, soit le plus approprié car ce sera le plus logique lorsque l’utilisateur va découvrir le processus.

Dans certains cas, modifier dynamiquement le comportement en fonction de l’état de la zone mise à jour est également possible, mais cela dépasse largement le cadre de cet article.

Conclusion

Ces quelques exemples simples montrent que la problématique de la reprise de focus est un élément central de l’accessibilité des interfaces. Lorsque cette problématique est ignorée ou comporte des failles, elle peut à elle seule rendre caduc tout le travail préalable de mise en accessibilité des contenus et des fonctionnalités.

Certains des problèmes les plus courants sont assez facilement détectés si on teste l’interface au clavier avec la touche de tabulation. En revanche, ce sera insuffisant pour détecter des problèmes plus subtils sur des fonctionnalités complexes ou qui peuvent adopter plusieurs comportements, en fonction de l’état des contenus par exemple.

Se poser la question de la gestion du focus au moment de la conception fonctionnelle est indispensable. En effet, c’est au moment où l’on décrit un processus pas à pas qu’on est le mieux placé pour savoir où doit être positionné l’utilisateur.

L’exemple de la gestion d’options de recherche ou de fonctionnalités de tri est, à ce titre, emblématique. Reporté sur l’ensemble d’une interface, le niveau de complexité peut très vite rendre impossible l’adaptation des mécanismes utilisés s’ils n’ont pas été correctement conçus.

La question « Où doit être mon utilisateur (focus) ? » est cruciale. Les UX designers et les développeurs devraient toujours la garder en tête, tant les conséquences d’une reprise de focus mal gérée peuvent être problématiques pour l’utilisateur.

C’est aussi dans ce genre de situation que le recours à des spécialistes du domaine prend tout son sens : ils pourront proposer les solutions les plus adaptées, trouver des palliatifs acceptables pour éviter des opérations de refonte coûteuses ou recourir à des tests utilisateurs dans les cas les plus complexes.