Un client dans l’univers du sport nous a signalé un comportement agaçant sur son site vitrine : le menu déroulant « Nos activités », construit sur mesure en Container Elementor avec un effet d’apparition au survol, restait grand ouvert après un tap sur mobile, recouvrant une partie du contenu de la page sans qu’aucun geste ne permette de le refermer autrement qu’en rechargeant la page.
Symptôme
Sur desktop, le menu fonctionnait parfaitement : survol de la souris pour ouvrir, déplacement du curseur ailleurs pour fermer. Sur mobile, un premier tap sur l’élément déclenchait bien l’ouverture, mais aucun geste ultérieur, ni un tap ailleurs sur la page ni un tap sur le menu lui-même, ne parvenait à le refermer. Seul un changement d’orientation de l’écran, par hasard, semblait parfois réinitialiser l’état visuel.
Diagnostic
Le menu avait été construit en Container plutôt qu’avec le widget natif Nav Menu, un choix fait à l’origine pour obtenir une mise en page très spécifique, avec des colonnes d’images à côté des liens du sous-menu. L’ouverture au survol reposait sur un pseudo-état CSS :hover classique, complété par une petite feuille de script gérant l’ajout d’une classe active au clic pour le comportement tactile, faute d’état hover natif sur mobile.
Le problème venait de la gestion de cette classe active : le script ajoutait la classe au premier tap sur l’élément déclencheur du menu, mais ne prévoyait aucun gestionnaire d’événement pour la retirer lors d’un tap en dehors du menu. Sur desktop, cette absence n’avait aucune conséquence puisque le CSS :hover gérait la fermeture naturellement au retrait du curseur. Sur mobile, sans curseur ni événement hover réel, la classe posée au premier tap restait indéfiniment active, puisque rien dans le code ne prévoyait sa suppression hors du périmètre du menu lui-même.

Correctif
La correction a consisté à ajouter un écouteur d’événement global sur le document, qui retire la classe active dès qu’un tap est détecté en dehors du conteneur du menu, en complément du gestionnaire existant sur le déclencheur lui-même.
document.addEventListener( 'touchstart', function ( event ) {
var menu = document.querySelector( '.menu-activites-container' );
if ( ! menu ) {
return;
}
var declencheur = menu.contains( event.target );
if ( ! declencheur ) {
menu.classList.remove( 'menu-actif' );
}
}, { passive: true } );
document.querySelectorAll( '.menu-activites-declencheur' ).forEach( function ( el ) {
el.addEventListener( 'touchstart', function () {
el.closest( '.menu-activites-container' ).classList.toggle( 'menu-actif' );
}, { passive: true } );
} );
Un point mérite attention dans ce correctif : l’ordre d’exécution entre les deux écouteurs. Sans précaution, le gestionnaire global de fermeture pouvait immédiatement annuler l’ouverture déclenchée par le tap sur le bouton lui-même, puisque les deux événements se déclenchent sur le même geste tactile. La vérification menu.contains( event.target ) règle ce conflit en excluant explicitement les taps survenant à l’intérieur du menu du déclenchement de la fermeture.
Prévention
- Sur tout menu personnalisé construit en Container plutôt qu’avec le widget natif, tester systématiquement le comportement tactile sur un vrai appareil, pas uniquement via l’émulateur mobile du navigateur, qui ne reproduit pas toujours fidèlement les événements tactiles réels.
- Prévoir dès la conception un gestionnaire de fermeture globale, pas seulement un gestionnaire d’ouverture, pour tout composant interactif basé sur une classe CSS plutôt que sur un état
:hovernatif. - Documenter dans le code du site pourquoi ce menu a été construit en Container plutôt qu’avec le widget Nav Menu natif, pour que la prochaine personne qui intervient comprenne le choix et ses implications.
Un menu qui fonctionne au survol sur desktop n’a pas d’équivalent tactile automatique. Chaque interaction pensée pour la souris mérite sa propre réflexion une fois transposée au doigt sur un écran tactile.
En résumé
Ce type de blocage touche presque toujours les menus personnalisés construits hors du widget Nav Menu natif d’Elementor, précisément parce que ce widget gère nativement la bascule entre comportement hover et comportement tactile. Sur un besoin de mise en page très spécifique qui justifie un menu maison en Container, prévoir explicitement la fermeture tactile dès la conception évite ce type de blocage découvert trop tard, en production.