aller au contenu principal

Des styles différents pour des états différents

Ne donne pas les mêmes règles CSS aux pseudo-classes :hover, :focus et :active


Publié le 17/09/2023 dans BlogMis à jour le 18/09/2023
Crédit photo - Unsplash - Luca BravoCrédit photo : Unsplash - Luca Bravo
Je suis en train d'écrire un cours complet sur Flexbox. Il y aura un module entier sur la compréhension de ce mode de layout, et un module 100% pratique avec plus d'une dizaine d'exercices.Tu peux consulter le programme et à te préinscrire dès maintenant ! ⬇️Se préinscrire

Récemment j'ai vu passé un tweet proposant une astuce pour regrouper en une seule classe les règles CSS pour les pseudo-classes :hover, et :focus.

Je ne suis pas d'accord avec cette astuce qu'il faut considéré comme une mauvaise pratique, et je vais t'expliquer pourquoi dans cet article.

L'astuce en question

Il s'agit d'une astuce pour Tailwind, qui permet, en passant par la création d'un plugin, de générer une classe CSS regroupant à la fois les styles du hover et du focus.

Ce qui évite d'avoir à écrire deux classes CSS différentes.

L'intention est louable car cette astuce permet d'écrire moins de classes (et dans Tailwind on en écrit des classes.. 🤡).

L'astuce permet de passer de ce code :

<button class="bg-blue-500
  hover:bg-blue-700 hover:text-white
  focus:bg-blue-700 focus:text-white">
  un bouton
</button>

à ce code :

<button class="bg-blue-500
  hover-focus:bg-blue-700 hover-focus:text-white">
  un bouton
</button>

Si tu ne connais pas Tailwind, c'est comme si on regrouper les pseudo-classes :hover et :focus de cette manière :

button:hover,
button:focus {
  /* les styles du hover et du focus ici */
}

Faire cela est considéré comme une mauvaise pratique, car on met les mêmes styles à des pseudo-classes qui ne servent pas les mêmes besoins.

La raison à cela est simple : les pseudo-classes :hover et :focus sont différentes, et elles ne doivent pas être utilisées dans le même contexte, car justement, le navigateur les détecte dans des contextes différents.

Je ne vais pas te mentir, j'ai moi aussi regrouper les styles de ces pseudo-classes pendant longtemps, en y ajoutant même la pseudo-classe :active, par flemme je l'avoue, mais aussi par méconnaissance de ces différents états.

Donc ceci est aussi à proscrire :

button:hover,
button:focus,
button:active {
  /* les styles du hover, du focus et du active ici 🤯 */
}

Pour vraiment comprendre pourquoi ce n'est pas une bonne pratique, il est donc important de comprendre comment fonctionne les différents états hover, focus et active dans le navigateur.

Ces trois états ont une pseudo-classe qui leur est associée, et qui porte le même nom : :hover, :focus et :active.

Ces pseudo-classes permettent de styliser un élément en fonction de son état, et ainsi, de donner de façon visuelle un retour à l'utilisateur sur l'état actuel de l'élément.

En général, l'état hover est plutôt bien compris, mais le focus l'est moins, et le active l'est encore moins !

Voyons ensemble comment ces états sont détectés par le navigateur et comment styliser intelligemment un élément en fonction de son état.


L'état et la pseudo-classe :hover

Quand on parle de l'état au hover d'un élément, on parle du survol de ce dernier à la souris.

L'état hover est déclenché quand le curseur de la souris survole un élément.

Donc quand un élément est survolé, les styles présents dans la pseudo-classe :hover sont appliqués.

Un exemple simple :

button {
  background-color: deepskyblue;
}

button:hover {
  background-color: tomato;
}

Par défaut, le bouton est bleu, mais quand on le survole avec la souris, il devient rouge.

Simple non ?

Tu peux faire le test ici :

Le hover ne fonctionne qu'avec la souris, il n'est pas déclenché sur un écran tactile.

Il permet d'envoyer un retour visuel à l'utilisateur, pour lui indiquer que le bouton "répond" au survol.

Cet état de survol et la pseudo-classe qui va avec sont plutôt simple à comprendre, passons au focus !

Le cas du hover "accidentel" sur mobile

Il est important de noter que sur mobile, le hover est déclenché au clic ("tap event").

C'est problématique, car cela peut déclencher des effets visuels non désirés.

Par exemple, si on a un bouton qui change de couleur au hover, et qu'on que l'on clique dessus sur mobile, il changera de couleur, ce qui peut être perturbant pour l'utilisateur.

Donc l'état hover peut être déclenché sur mobile.

Mais.. tu as dis : "Le hover ne fonctionne qu'avec la souris".. 🤔

Quand on parle de hover, on parle de survol, et le survol n'est pas possible sur mobile.

Mais sur mobile, le "tap event" déclenche l'état hover, au même titre qu'il déclenche le clic.

Donc si on crée un bouton qui doit rediriger l'utilisateur vers une autre page, l'effet du hover sera visible sur mobile quand l'utilisateur va appuyer sur le bouton.

J'appelle cela : le hover "accidentel".

Il existe une solution pour éviter cela : faire une Media Query qui cible seulement les appareils qui permettent le survol :

@media (hover: hover) {
  button:hover {
    background-color: #3b98ff;
  }
}

Voici un exemple interactif, tu devrais pouvoir déclencher l'état hover sur mobile sur le premier bouton, mais pas sur le second :


L'état et la pseudo-classe :focus

Le focus est détecté quand un élément reçoit un focus, autrement dit, quand il est sélectionné.

On peut sélectionner un élément de plusieurs façons, en utilisant la touche tabulation du clavier, ou en cliquant dessus.

Tous les éléments ne peuvent pas recevoir un focus, voici ceux qui le peuvent :

  • les éléments de formulaire : input, textarea, select, etc.
  • les éléments avec un attribut tabindex
  • les liens (<a>)
  • les boutons (<button>)

Quand un utilisateur sélectionne un élément, il est important de lui donner un retour visuel, pour lui indiquer que l'élément est sélectionné.

Ce retour visuel doit être différent du hover, car ce n'est pas le même état.

D'autant plus qu'un utilisateur qui navigue au clavier, ne peut pas déclencher de hover, et il ne peut pas savoir à l'avance quel élément va recevoir un focus.

C'est pour cela qu'il est recommandé de mettre des styles qui vont attirer l'œil, comme une animation sur la propriété outline ou box-shadow.

Voici un exemple :

button {
  background-color: deepskyblue;
}
button:hover {
  background-color: tomato;
}
button:focus {
  outline: 3px solid lightsalmon;
}

La propriété outline est un très bon choix, car comme box shadow, elle n'affecte pas le layout, c'est à dire qu'elle ne va pas déplacer les éléments qui sont autour comme la propriété border le ferait.

Passons maintenant à l'état actif, qui est le plus méconnu des trois.


L'état et la pseudo-classe :active

L'état actif est détecté quand un élément est actif, autrement dit, quand on clique dessus.

Pourtant le focus est aussi détecté quand on clique sur un élément, alors pourquoi ne pas utiliser le focus pour styliser un élément actif ? 🤪

C'est une bonne reflexion, mais il faut bien comprendre que le focus est détecté quand un élément est sélectionné, et il peut être sélectionné par le clic comme on l'a vu, mais il n'est pas actif pour autant.

Même si on peut déclencher le focus avec un clic, c'est juste une sélection, l'élément n'est pas actif lorsqu'il est focus.

Cependant il faut noter que lorsqu'on clique sur un élément, il reçoit un focus, et le temps du clic, ce dernier est actif.

Donc un élément reste actif quand le clic est maintenu enfoncé, et il ne l'est plus quand on relache le clic. Pour la navigation au clavier, c'est la touche espace qui permet de déclencher l'état actif.

Voici un exemple :

button {
  background-color: deepskyblue;
}
button:hover {
  background-color: tomato;
}
button:focus {
  outline: 3px solid lightsalmon;
}
button:active {
  outline-offset: 3px;
  outline-color: orangered;
  background-color: orangered;
}

Tu peux voir que ça commence à faire pas mal de règle CSS juste pour un bouton, mais si tu peux le faire dans un projet, il ne faut pas hésiter.

Tu peux tester avec le bouton ci-dessous tous les comportements et noter les choses suivantes :

  • ✅ l'état hover est détecté quand on survole le bouton avec la souris.
  • ✅ l'état focus est détecté quand on sélectionne le bouton avec la touche tabulation, ou lorsqu'on clique dessus (ce qui a aussi pour conséquence de déclencher l'état actif), tu noteras que le focus disparait quand tu cliques ailleurs que sur le bouton.
  • ✅ l'état actif est détecté quand on clique (ou qu'on appuit sur la touche espace) sur le bouton, l'élement n'est plus considéré comme actif lorsqu'on lache le clic, ou lorsqu'on lache la touche espace.

Regrouper les pseudo classes :hover et :active

Parfois, regrouper les styles des pseudo-classes :hover et :active peut avoir du sens.

Oui j'ai dit qu'il ne fallait pas le faire, mais c'était seulement pour le hover et le focus !

Dans le cas d'un bouton cela a du sens :

button:hover,
button:active {
  background-color: blue;
}

button:focus {
  outline: 2px solid blue;
}

L'important est de savoir si l'utilisateur reçoit une information visuelle en fonction de son interaction avec le bouton.

S'il navigue à la souris :

  • ✅ il reçoit bien un retour visuel au hover car la couleur de fond du bouton change s'il le survole avec sa souris.
  • ✅ il reçoit bien un retour visuel au clic car le bouton recevra un focus et une bordure apparaitra (avec outline).

S'il navigue au clavier :

  • ✅ il reçoit bien un retour visuel au focus car le bouton recevra un focus et une bordure apparaitra (avec outline).
  • ✅ il reçoit bien un retour visuel lorsqu'il interagira avec (avec la touche espace) et le bouton changera de couleur de fond.

Tu peux tester ces comportements ici :

C'est un exemple qui je trouve à du sens, mais on peut voir les choses différement et avoir des styles pour le hover et le active séparés !

En général j'essaye de mettre des styles différents sur les 3 pseudo-classes.

Mais parfois ce n'est pas nécessaire de toutes les utiliser, et je vais t'expliquer pourquoi.


Faut-il styliser les pseudo-classes :hover, :focus et :active tout le temps ?

Alors cette question peut faire débat, mais personnelement je ne stylise pas l'état actif sur certains éléments de formulaire comme les <input />.

Cela peut donner un effet visuel momentané lorsque un utilisateur qui navigue à la souris va cliquer dessus, il est important de considérer l'accessibilité et l'utilité de cet effet.

Je trouve que c'est pertinent sur un bouton, mais pas sur un champ de formulaire.

J'essaye de garder en tête qu'il faut faire des choses logiques et qui ont un réel intérêt pour l'utilisateur.

Alors pour un champ, on peut montrer un changement au survol et au focus seulement.

Voici un petit exemple avec deux champs pour illustrer mes propos :

❌ Avec du CSS sur la pseudo-classe :active

✅ Sans CSS sur la pseudo-classe :active

J'ai choisi des couleurs bien différentes, le résultat n'est pas très esthétique mais il permet de bien comprendre l'exemple.

Sur le premier champ, on peut voir que lorsqu'on clique dessus, et qu'il devient actif, il change de couleur de fond, juste le temps du clic, je trouve que c'est inutile et que ça peut même être perturbant pour l'utilisateur.

Donc autant de pas utiliser la pseudo-classe :active sur les champs de formulaire.

Tu noteras également la présence d'un effet au survol, celui-ci est important car il permet de montrer à l'utilisateur qu'il peut interagir avec le champ.

Voici le code CSS des deux exemples, le premier avec la pseudo-classe :active :

input {
  border: 1px solid deepskyblue;
}
input:hover{
  border-color: lightsalmon;
}
input:focus {
  outline: 3px solid lightsalmon;
}
input:active {
  background-color: tomato;
}

Celui-ci sans la pseudo-classe :active :

input {
  border: 1px solid deepskyblue;
}
input:hover{
  border-color: lightsalmon;
}
input:focus {
  outline: 3px solid lightsalmon;
}

Les navigateurs peuvent avoir des comportements différents

En fonction du navigateur que tu utilises, tu n'auras peut-être pas le même comportement sur certains états.

Cet article se veut généraliste donc je ne vais pas rentrer dans des spécificités, mais pour te donner un exemple : sur Safari, les boutons ne peuvent pas recevoir de focus, c'est un choix de design assumé.


Conclusion

Avec ce que l'on a vu dans cet article, tu comprends maintenant que l'idée de regrouper les pseudo-classes :hover et :focus n'est pas une bonne pratique. 😠

Tu sais également que :

  • les navigateurs sont capables de détecter des états différents.
  • ces états ont des pseudos-classes qui leur sont associées, et qui permettent de styliser un élément en fonction de son état.
  • il ne faut pas regrouper les pseudo-classes :hover et :focus car elles ne servent pas les mêmes besoins.
  • il est possible de regrouper les styles des pseudo-classes :hover et :active si cela a du sens.
  • la pseudo-classe :active n'est pas toujours nécessaire, ce n'est pas parce qu'on met du CSS sur toutes les pseudo-classes qu'on fait les choses bien, il faut penser à l'accessibilité et à l'utilité de ce qu'on met en place.

Pour terminé, si cet article t'as plu, tu peux le partager pour m'aider à donner plus de visibilité à mon travail. 🥰

Tu peux aussi t'inscrire à ma newsletter via le formulaire juste en-dessous pour recevoir mes emails et être prévenu de la sortie des prochains articles !

Seb.

D'autres articles qui peuvent t'intérésser :

2024 Sébastien Imbert