Créer un menu de navigation mobile
Cela fait un bon petit moment que j’explore les différentes techniques de navigation existantes pour sites web mobiles.
Les possibilités sont nombreuses et aucune n’est magique, cela dépend du contexte et du projet.
Cependant, j’ai pensé qu’il pouvait être utile de décortiquer une technique parmi d’autres.
Voici donc mon essai de menu de navigation pour mobile.
Et voici comment j’ai procédé…
Première étape : définir les contraintes et les objectifs
Le comportement de mon menu doit être celui-ci sur mobile : par défaut, les éléments de navigation seront masqués (repliés), et un bouton “menu” indique une action à effectuer pour le faire apparaître.
Lors du clic (ou touch) sur le lien “menu”, le menu se déploie en transition, en poussant vers le bas le reste de la page.
Je me suis posé un certain nombre de contraintes que devra respecter mon menu de navigation :
- le menu doit être complètement autonome,
- la structure HTML doit être aussi propre et “sémantique” que possible,
- aucun JavaScript ne doit être chargé et exécuté pour des raisons de performances web,
- dans la même optique : pas d’image, ni de font-icon, ni de sprite,
- aucune requête HTTP, aucun fichier à télécharger ou interpréter,
- aussi accessible que possible (via lecteurs vocaux de type VoiceOver),
- compatible sur le plus de navigateurs mobiles possible (tout en demeurant fonctionnel si certaines parties ne sont pas supportées),
- tout ça sans peser 3Mo ! :)
Deuxième étape : la structure HTML
Le code HTML du menu de navigation est aussi simple que prévisible : un conteneur nav dans lequel on trouve la liste ul/li des éléments
<nav role="navigation"> <ul> <li><a href="#">Salade</a></li> <li><a href="#">Tomate</a></li> <li><a href="#">Oignons</a></li> <li><a href="#">Choucroute</a></li> <li><a href="#">Picon bière</a></li> </ul> </nav>
Puisqu’on est sur terminal mobile, on adapte la taille du Viewport (dans le head) :
<meta name="viewport" content="initial-scale=1.0">
Pour indiquer à l’utilisateur comment va se comporter le menu, rien de tel qu’un symbole représentant une flèche.
Pour cela, Unicode est parfait puisque vous n’aurez même pas à télécharger une image :
nav:before {
content: "Menu \25BC";
display: block;
padding: .8em;
background: #2B4244;
color: #fff;
}
Troisième étape : l’habillage succinct en CSS
Un coup de CSS3 Media Queries pour styler les éléments en condition d’affichage mobile :
@media (max-width: 800px) {
...
}
Des styles minimum pour apporter un peu de cosmétique (couleurs de fond, marges, etc.) :
nav ul {
max-height: 0; /* menu masqué */
overflow: hidden;
margin: 0; padding: 0;
list-style: none;
}
nav a {
display: block;
padding: 0.8em;
background: #4A7377;
color: #fff;
text-decoration: none;
}
On aboutit à un résultat acceptable. Il ne reste plus qu’à gérer l’événement qui va déclencher l’affichage et le masquage du menu…

Quatrième étape : l’événement “touch” avec CSS :focus
:focus est une pseudo-classe finalisée depuis longtemps en CSS. Elle permet de cibler les éléments ayant le focus (lorsqu’il est atteint par le dispositif de pointage), par exemple sur les champs de formulaires.
Nous allons tirer profit de cet avantage pour cibler le menu de navigation lors du clic / touch sur le lien prévu.
Les éléments de formulaires et les liens bénéficient naturellement de l’événement :focus. Pour les autres, il faut leur attribuer un attribut tabindex :
<nav tabindex="0" ... >
Les CSS en action pourraient ressembler à ça :
nav:focus ul {
max-height: 25em; /* je fais apparaître la liste lorsque je donne le focus à nav*/
}
Nous allons cependant compliquer quelque peu la syntaxe pour pallier les déficiences navigateurs.
En effet, je souhaite que dans le cas où un navigateur ne reconnaît pas la pseudo-classe :focus, le menu soit tout de même fonctionnel (et donc pas masqué).
C’est pour cela que je vais prendre le problème à l’envers et afficher par défaut le menu déployé. Ce n’est que lorsque la cible ne sera pas :focus qu’elle sera masquée. Bref, on va employer une combinaison (déjà évoquée précédemment) entre le sélecteur de négation :not() et :focus.
nav:not(:focus) ul {
max-height: 0;
}
Et voilà, le plus compliqué est fait !
BONUS : le petit truc en plus pour faire fonctionner le clic / touch sur certains navigateurs récalcitrants (Opera Mini par exemple) est d’ajouter un événément onclick=”“ sur le lien du menu.

En guise de bonus, ajoutons une petite transition sur l’événement :
nav ul {
max-height: 25em; /* number of items x5 */
-webkit-transition: max-height .4s;
transition: max-height .4s;
}
BONUS : pour faciliter les performances d’affichages sur mobile, il est de bon ton d’activer l’accélération matérielle et de décharger le CPU. L’un des moyens d’y parvenir est d’appliquer une déclaration transform: translateZ(0); sur l’élément qui bénéficie de la transition :
nav ul {
-webkit-transform: translateZ(0); /* activating hardware acceleration */
-ms-transform: translateZ(0);
transform: translateZ(0);
}
Et voilà mon menu “responsive” est pleinement opérationnel !
Inconvénients
Les avantages sont nombreux et évoqués en début d’article (pas de JavaScript, pas d’image ni autre requête HTML, pas d’éléments HTML parasites ou non sémantiques)
Les inconvénients sont :
- Non compatible sur anciens smartphones, par exemple Android 2.3 et inférieur
- Navigation non fonctionnelle au clavier (ce qui me semble assez inutile sur smartphone et tablettes)
- Le menu ne se referme pas en re-cliquant sur “Menu”. Il faut cliquer sur un autre lien de la page (par exemple celui du titre de page) pour le refermer.

En terme de compatibilité, le menu est fonctionnel sur bon nombre de navigateurs de smartphones et tablettes (à partir d’Android 3 minimum tout de même).
Si vous souhaitez mettre en place un menu de navigation dans un souci de compatibilité maximale, je vous propose une variante: le même menu de navigation, basé sur un événement :hover à la place de :focus: , reconnu dès Android 2.1 : http://goetter.fr/nav2/