Web : hover sur du tactile
Mon application de gestion/lecture de bédés doit fonctionner à la fois sur tablette et sur pc/portable, donc réagir à des interactions de souris et des événements tactiles, ce qui peut parfois entrainer des soucis. C'est le cas par l'exemple pour l'état hover
.
État transitoire hover
L'état hover
est un état transitoire d'un élément d'une page web acquis lorsque la souris passe au-dessus de lui. On peut y appliquer des styles :
.my-element:hover {
/* rules */
}
On peut aussi lui appliquer des traitements dynamiques en javascript :
myElement.addEventListener('mouseover', e => {
// actions
});
Noter cependant que les deux codes ne sont pas équivalents : en css, les styles hover
disparaitront dés que la souris quitte l'élément ; les actions effectuées dans l'écouteur d'événement mouseover
elles ne s'annuleront pas. Il faut pour cela écouter l'événement mouseout
(ou opter pour le couple mouseenter
/mouseleave
qui évite certains effets de bords de mouseover
/mouseout
).
Hover dans un périphérique tactile
Le problème que pose un style hover
sur un périphérique tactile, c'est qu'il est appliqué lorsque l'utilisateur commence une interaction tactile sur l'élément qui le porte, mais qu'il n'est pas forcément « relâché » quand cette interaction se finit.
Exemple pratique dans l'application de gestion/lecture de bédés : la partie gauche de la page sert à afficher l'arborescence des fichiers au-dessus de la bédé. Sur un pc/portable, il suffit de passer la souris près du bord gauche et le panneau s'ouvre (hover
). Sur un écran tactile, il faut faire un geste de gauche vers la droite sur la partie gauche l'écran ; un mouvement dans le sens inverse le referme.
Résultat : quand on a fait un mouvement tactile pour ouvrir le panneau latéral, il devient très souvent compliqué de le refermer par le mouvement inverse parce que les styles hover
(panneau ouvert) restent appliqués.
Quelques solutions
La solution ? Ne pas appliquer les styles hover
quand on est sur un périphérique tactile. Pour cela, on va détecter non pas ce que le périphérique est (un pc, un portable, une tablette, un téléphone) mais plutôt ce que le navigateur qu'il embarque sait faire.
Ainsi, une première approche consiste à demander au navigateur web s'il sait gérer les événements tactiles :
/**
* If web browser can listen to touch events
* @type {boolean}
*/
const hasTouch = 'ontouchstart' in globalThis.document.documentElement;
Cette solution peut ne pas marcher : le navigateur web de ma tablette ubuntu répondait toujours « false » alors même que le tactile fonctionne.
Alternative : demander au navigateur s'il sait gérer le hover
:
/**
* If web browser can handle :hover state
* @type {boolean}
*/
const hasHover = globalThis.matchMedia('(hover: hover) and (pointer: fine)').matches;
Les caractéristiques @media hover
et pointer
peuvent évidemment être directement utiliser en css :
@media (hover: hover) and (pointer: fine) {
/* styles only for hover web browsers */
}
Là encore, tester simplement la gestion de hover
n'a pas suffit : le navigateur de la tablette répondait "oui". Il a fallu passer par la caractéristique @media pointer
, qui permet de savoir si un mécanisme de pointage précis (comme une souris) est présent. On pourra même utiliser quelque chose de plus générique comme any-pointer
.
Voici résumé les différents tests effectués sur un pc (Firefox sous Fedora) et sur une tablette (navigateur basée sur webkit sous Ubports) :
@media | Tablette | PC |
---|---|---|
any-hover: none | FALSE | FALSE |
any-hover: hover | TRUE | TRUE |
hover: none | FALSE | FALSE |
hover: hover | TRUE | TRUE |
any-pointer: none | TRUE | FALSE |
any-pointer: fine | FALSE | TRUE |
pointer: none | TRUE | FALSE |
pointer: fine | FALSE | TRUE |