Le focus n’est pas juste une astuce !

Il est important de s’assurer qu’un site web soit navigable par clavier. C’est un des critères d’accessibilité qu’il faut avoir constamment en tête.

2.4.7 Focus Visible : Any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible (Level AA). WCAG 2.0

Pour cela, un liseré est visible autour de chaque élément interactif recevant un focus tels que les liens, les boutons, ou certains éléments de formulaire. Contrairement aux bordures, le liseré ne fait pas partie du box model, il ne prend donc pas d’espace supplémentaire. C’est ce que l’on nomme l’outline.

Certaines personnes, en situation de handicap ou qui ont une déficience, ne peuvent pas forcément user de dispositifs de pointage pour des raisons spécifiques qui leur sont propres. Ils ont donc besoin d’avoir cette information visuelle afin de leur permettre de se situer au sein de la page.

Malheureusement, pour des questions de design, on a souvent la demande de supprimer ce focus, ce qui nuit à l’accessibilité du site. Plusieurs possibilités existent en CSS pour nous aider à styler les éléments focalisables, dont les nouvelles pseudos-classes :focus-ring et :focus-within, issues des spécifications CSS4, qui sont très prometteuses pour le futur. C’est ce que nous allons voir par la suite.

Éviter outline : none, please !

Nous l’avons tous fait à un moment ou un autre. Le but étant de contrôler spécifiquement le focus sur certains éléments HTML ou simplement de maintenir une cohérence visuelle avec la charte graphique. En effet, le style du focus par défaut du navigateur, en général, ne plaît pas et donc ne s’intègre pas avec les designs d’aujourd’hui. Par conséquent, cela amène à appliquer cette propriété CSS :

:focus { outline: none; }

Pire encore, les événements en JavaScript pour supprimer le focus, comme l’événement onfocus(), font que les utilisateurs du clavier ne peuvent plus interagir avec l’élément html.

onfocus = "blur()"

Les styles du focus sont primordiaux pour afficher visuellement quel élément focalisable est actuellement sélectionné. Les utilisateurs de souris ou de trackpad n’ont pas trop à s’inquiéter à ce sujet parce que leur regard suivent le curseur pendant qu’il se déplace dans la page. De plus, le curseur peut prendre différentes formes en fonction de l’action attendue par l’utilisateur.

Pour les utilisateurs de clavier, par contre, cette fonctionnalité est très utile. En utilisant la touche de tabulation, on se déplace dans la page et cela permet de se repérer plus précisément, de naviguer et d’accéder aux contenus. L’enlever, c’est supprimer un mécanisme d’accessibilité important pour ces utilisateurs. Cela rend la navigation extrêmement difficile, voire impossible.

Concilier accessibilité et design

Plusieurs solutions existent pour conserver cette fonctionnalité intacte tout en l’intégrant à l’interface graphique :

1- Styler le contour

"Lorem ipsum dolor sit amet" encadré d'un filet

Tous les navigateurs n’obtiennent pas le même rendu de la propriété outline. Le site allyjs.io référence les différents rendus de cette propriété suivant les navigateurs et la plateforme. On peut voir que les navigateurs Webkit sur Mac ont une lueur de couleur bleue plus importante. On peut donc essayer de styliser cet élément pour atténuer cet effet et uniformiser. Pour cela, on pourrait ainsi penser à redéfinir les propriétés outline-style, outline-width et outline-color, qui gèrent respectivement le style, la largeur et la couleur du contour, pour normaliser son aspect sur les navigateurs.

:focus {outline: thin dotted orange; }

2- Styliser l’élément html lui-même

Lorem ipsum dolor sit amet

On peut supprimer le contour, à condition de redéfinir un nouveau style css alternatif pour celui-ci. En général, lorsque que l’on définit un état :hover sur un élément, on applique ce même style au focus.
L’avantage d’employer cette méthode réside dans la marge de manœuvre qui est plus importante. Les possibilités s’élargissent afin de proposer un rendu graphique cohérent car nous avons la capacité d’agir sur plusieurs aspects :

  • le soulignement
  • les bordures
  • la couleur de texte
  • la couleur de fond
  • la graisse

a:hover, a:focus {
   outline: none;
background-color: black;
color: white;
}

Par contre, il faut être vigilant.
La règle outline: none; ne doit jamais être appliquée par défaut dans la CSS (dans un normalize.css ou un reset.css), sauf dans les cas très précis où la visibilité du focus est ensuite surchargée dans la feuille de style, comme ci-dessus.
Mais il faut veiller à appliquer ces nouveaux styles partout où le focus doit être redéfini.

3- Styliser le contour en distinguant les utilisateurs de clavier et de souris

Lorsqu’un utilisateur interagit avec la page en utilisant la souris, il n’est parfois pas nécessaire de montrer les styles du focus.
Dans ce cas, l’idéal serait de supprimer les contours pour les utilisateurs de souris uniquement, si l’on doit vraiment le faire. Ainsi, si une interaction avec le clavier est détectée, on active le contour, sinon on ne l’affiche pas.
Cette subtilité sera possible prochainement avec la pseudo-classe :focus-ring, qui fait partie de la spécification des sélecteurs CSS Level 4.

/* On supprime le contour par défaut */
:focus {
outline: none;
}

/* On définit un contour seulement lorsqu'il devrait être visible */
:focus-ring {
outline: 2px solid blue;
}

Malheureusement, pour le moment, aucun navigateur ne supporte l’implémentation standard de cette propriété, mais il existe déjà un polyfill léger qui ajoutera une classe .focus-ring lorsque le contexte sera approprié.

On peut également le faire d’une autre manière : en JavaScript, on ajoute un attribut au corps de la page, permettant ainsi d’écrire du CSS qui sera activé seulement si l’utilisateur utilise le clavier pour naviguer. What-input fonctionne de cette manière et fait partie de ces alternatives que l’on peut utiliser.

Mais il faut considérer cette ultime solution en dernier recours. En effet, certains navigateurs ou lecteurs d’écran peuvent déclencher des événements de souris, ce qui peut entraîner la disparition des contours lors de l’utilisation de cette méthode.

4- Styliser les élément avec des descendants ciblés

La sélection d’un élément parent a longtemps été impossible à faire en utilisant seulement la CSS, mais une nouvelle pseudo-classe :focus-within change un peu la donne. On va pouvoir désormais appliquer un style à un élément quand il a un focus, mais aussi quand l’un de ses descendants a un focus. Et aujourd’hui, c’est déjà supporté par la plupart des principaux navigateurs !

Cela va s’avérer notamment utile lorsqu’on souhaite, par exemple, mettre en avant l’ensemble d’une zone d’un formulaire lorsque l’utilisateur prend le focus sur l’un de ses éléments. On pourrait faire la même chose dans le cas d’un tableau afin de mettre en avant les lignes ou les colonnes. Cela supprimera le besoin de JavaScript souvent utilisé pour obtenir cet effet.

See the Pen Focus-within by example : form by Josiane Makelele (@josy-star) on CodePen.

Dans ce code, on peut remarquer comment la couleur d’arrière-plan est appliquée à l’élément conteneur lorsque l’un des champs est focalisée.
Si on avait utilisé la pseudo-classe :focus au lieu de :focus-within, cela aurait été différent. D’abord, il aurait fallu ajouter l’attribut tabindex sur la div conteneur pour qu’elle soit focalisable. Ensuite, le conteneur ne serait stylisée que lorsque le focus est positionné sur lui-même, mais pas lorsque les enfants (ici les balises <input>) sont focalisées. Donc, ce n’est pas le même rendu et pas vraiment ce qui est désiré.

See the Pen Focus-within by example : dropdown menu by Josiane Makelele (@josy-star) on CodePen.

Cela concerne les menus avec liste déroulante. Avant, le JavaScript était nécessaire pour savoir quand le focus clavier d’un utilisateur se trouvait sur l’un des menus déroulants de navigation. Sans ce traitement, il n’était pas possible d’ouvrir le menu déroulant et de naviguer au clavier à l’intérieur. Aujourd’hui, avec :focus-within, plus besoin de JavaScript !

C’est pourquoi, afin que cette pseudo-classe :focus-within fonctionne comme prévu, il faut s’assurer que :

  • Les éléments enfants du conteneur soient focalisables. Si ce n’est pas le cas, l’attribut tabindex peut être utilisé pour rendre un élément focalisable ;
  • L’élément conteneur soit focalisable pour recevoir le style au moment du focus.

C’est assez puissant et c’est pour cela qu’il faut l’utiliser avec parcimonie. Cela risque d’être difficile à gérer si l’on a un élément qui contient beaucoup de sous-composants qui contiennent aussi des éléments enfants focalisables. Ce sera donc au cas par cas qu’il faudra voir si cette pseudo-classe est pertinente ou non.

Pas de suppression mais toujours des alternatives.

Appliquer un focus n’est pas une option, mais un critère d’accessibilité de niveau AA. En utilisant la propriété outline: none; sans fallbacks appropriés, cela rend le site significativement moins accessible à tout utilisateur qui navigue par clavier, et qui en nécessite le besoin. Il faut s’assurer de toujours donner aux éléments interactifs une indication visible du focus. Des choix techniques sont à notre disposition, c’est en constante évolution et des nouveautés restent encore à venir. Mais c’est prometteur et on peut déjà en utiliser certaines en production. En attendant, c’est à nous de prendre en main ces outils et de les utiliser consciencieusement pour pouvoir répondre aux attentes de chacun.

3 commentaires sur cet article

  1. Yvain, le jeudi 28 décembre 2017 à 09:53

    Bonjour,

    ”:focus-ring” a été récemment renommé en ”:focus-visible” https://github.com/w3c/csswg-drafts/pull/2104 et ce quasiment en même temps que la publication ce cet article.

    Le polyfill va être mis à jour dans ce sens https://github.com/WICG/focus-ring/pull/90

    Il en sera surement de même pour le plugin postcss https://github.com/jonathantneal/postcss-focus-ring/issues/1

  2. MAKELELE Josiane, le mardi 16 janvier 2018 à 16:17

    Oui effectivement, le changement a été fait au même moment.
    Merci pour ces dernières informations !

  3. Yvain, le lundi 19 février 2018 à 11:18

    Les 2 modules pour ”:focus-visible” sont maintenant à jour.

    https://www.npmjs.com/package/focus-visible
    https://www.npmjs.com/package/postcss-focus-visible