Il s'agit d'un menu dont seuls les items secondaires sont des liens (pas les titres de catégorie). J'ai choisi d'utiliser des sections contenant un titre et une liste, plutôt que de faire une liste de listes comme on le voit souvent.
<nav class="menu"> <section class="categorie"> <h3>Rubans</h3> <ul> <li><a href="">Tagliatelle</a></li> <li><a href="">Fettuccine</a></li> <li><a href="">Lasagne</a></li> </ul> </section> <section class="categorie"> <h3>Ficelles</h3> <ul> <li><a href="">Spaghetti</a></li> <li><a href="">Spaghettoni</a></li> <li><a href="">Vermicelli</a></li> <li><a href="">Capellini</a></li> </ul> </section> <section class="categorie"> <h3>Tubes</h3> <ul> <li><a href="">Macaroni</a></li> <li><a href="">Cannelloni</a></li> <li><a href="">Penne</a></li> <li><a href="">Cavattapi</a></li> </ul> </section> <section class="categorie"> <h3>Autres</h3> <ul> <li><a href="">Farfalle</a></li> <li><a href="">Fusilli</a></li> <li><a href="">Ravioli</a></li> <li><a href="">Gnocchi</a></li> <li><a href="">Conchigliette</a></li> </ul> </section> </nav>
Pour le CSS, j'utilise du inline-block
pour simplifier
l'exemple.
.menu { border: 1px solid black; } .menu .categorie { border: 1px solid red; display: inline-block; vertical-align: top; } .menu .categorie ul { background-color: lightgreen; }
NB : j'ai mis une classe categorie
aux catégories, que j'utilise dans le CSS au lieu
du sélecteur d'élément section
. Cela rend le CSS plus clair et moins dépendant du HTML.
On met tout simplement le sous-menu en display:none
par défaut, et en display:block
quand son parent
(la section de classe categorie
) est survolé.
.menu .categorie ul { display: none; } .menu .categorie:hover ul { display: block; }
Cependant, ça ne suffit pas, car l'apparition des sous-menus décale le reste de la page.
.menu .categorie ul { position: absolute; }
Pour éviter le problème de la section précédente, j'ai mis les sous-menus en position:absolute
.
Comme je n'ai pas utilisé de décalage (avec les propriétés top
, left
, etc.),
ils ne changent pas de position ; cependant, ils sont sortis du « flux » normal de la page,
leur apparition ne fait donc rien bouger.
On peut cependant remarquer que leur largeur ne dépend plus de celle de leur parent. On va voir deux solutions dans la suite.
Le CSS ci-dessous reprend les quelques règles permettant d'obtenir un menu déroulant, et ajoute un peu d'habillage au menu.
En particulier, on prend soin de présenter de la même façon les éléments h3
(titres des catégories) et les liens eux-mêmes (sauf en ce qui concerne le survol).
On utilise un width
fixé (ici à 10em) pour que les sous-menus soient de même taille que les titres de catégorie.
.menu { text-align: center; } .menu .categorie { display: inline-block; vertical-align: top; background: lightblue; } .menu .categorie ul { display: none; position: absolute; padding: 0; margin: 0; list-style: none; } .menu .categorie:hover ul { display: block; } .menu h3, .menu a { display: block; margin: 0; padding: .5em 1.5em; font-size: inherit; color: black; background-color: lightblue; text-decoration: none; box-sizing: border-box; width: 10em; } .menu .categorie:hover h3 { color: white; background-color: steelblue; } .menu a:hover { color: white; background-color: skyblue; }
Utiliser inline-block
est pratique, mais n'est pas très propre pour une mise en page précise,
car les espaces dans le HTML apparaissent dans le rendu entre les items.
Le CSS ci-dessous utilise une grille CSS pour créer un menu déroulant dont chaque item fait exactement un quart de la largeur disponible, et ajoute une animation au déroulement du menu.
.menu { text-align: center; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; } .menu .categorie { background: lightblue; position: relative; /* pour être la «racine» du sous-menu en absolute */ } .menu .categorie ul { max-height: 0; overflow: hidden; transition: 0; position: absolute; padding: 0; margin: 0; list-style: none; width: 100%; /* pour avoir la même largeur que la «racine» */ } .menu .categorie:hover ul { max-height: 50em; transition: 1s; } .menu h3, .menu a { display: block; margin: 0; padding: .5em 1.5em; font-size: inherit; color: black; background-color: lightblue; text-decoration: none; box-sizing: border-box; } .menu .categorie:hover h3 { color: white; background-color: steelblue; } .menu a:hover { color: white; background-color: skyblue; }
Plusieurs points à noter :
On donne au ul
une largeur de 100%, pour le forcer à avoir la même largeur que la section
,
mais ça ne suffit pas : si on ne fait que ça, il va prendre 100% de la largeur de la fenêtre…
Il faut établir la section
comme référent («racine») du sous-menu en position absolue.
Pour cela, il suffit de le mettre en position:relative
: ça n'a aucun effet sur sa position, seulement
sur le comportement de ses descendants qui sont en position:absolute
(voir démos du cours sur la mise en page).
Pour bien comprendre tout cela, le plus efficace est de tester soi-même :
enlevez le position:relative
des catégories ; et regardez ce qui se passe !
Comme on ne peut pas animer le passage de display:none
à
display:block
, il faut choisir un autre moyen de cacher le menu. Une façon classique est de mettre
le max-height
à 0 par défaut, et à une grande valeur au survol (ici 50em
: si votre sous-menu est plus haut que 50 lignes de texte,
vous avez de toute façon un problème d'ergonomie à régler). Évidemment il faut aussi cacher le contenu qui dépasse (overflow:hidden
),
pour que rien n'apparaisse par défaut.
NB : j'ai utilisé une transition instantanée pour le repliement, c'est plus agréable à manipuler. De manière générale, c'est une bonne idée d'éviter de continuer à montrer trop longtemps à l'internaute quelque chose qu'il ou elle ne veut plus voir.