Un menu déroulant
Ce billet explique la réalisation d'un menu déroulant et illustre les définitions vues dans les billets :
L'objectif est de réaliser la page affichée ci-dessous.
Comme l'illustre l'image ci-dessus, la page est constituée de 3 "blocs" (balise html div) identifiés respectivement element1, menu et element2. Ils seront donc stylisés dans le CSS par respectivement #element1, #menu, #element2 avec un fond coloré background-color: qui permet de vérifier qu'ils s'empilent les uns sous les autres (même si, comme c'est le cas pour le bloc menu dont la largeur est limité à 70% de la page - width:70% - , ils n'occupaient pas toute la largeur de la page) conformément aux caractéristiques des types "bloc".
Le squelette du code montre les 3 blocs du corps de la page :
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="element1">ce bloc 1 est bleu </div>
<div id="menu" >ce bloc 2 contient le menu ------- </div>
<div id="element2">ce bloc 3 est rouge </div>
</body>
</html>
Le bloc menu utilise "display:flex" pour que ses éléments (le texte et le bloc du menu "balise html ul" ) soient en ligne.
#menu {
display:flex;
width:70%;
margin:0px 0px 0px 0px;
background-color:beige;
}
Le squellette du code du menu montre une balise ul encadrant une succession de bloc li, un bloc li pour chaque item du menu.
<ul class="r0">
<li> ... </li>
<li > ... </li>
<li > ... </li>
</ul>
La classe r0 de ce menu permet l'alignement horizontal des items du menu : la liste des <li>.
#menu .r0 {
display:flex;
flex-direction: row;
}
Chaque balise li contient un lien et éventuellement un sous-menu formé par un bloc ul. Ces balises <ul> imbriquées forment les différentes profondeurs du menu et sont, chacune, stylisées par une classe repérant la profondeur du menu.
- r0 la racine du menu ;
- r-1 le 1er niveau ;
- r-2 le second niveau.
<div id="menu" >ce bloc 2 contient le menu
<ul class="r0">
<li>
<a href="#"> menu racine </a>
<ul class="r-1">
<li>
<a href="#">menu profondeur1 -a</a>
<ul class="r-2">
</ul>
</li>
<li >
<a href="#"> menu profondeur1 -b</a>
<ul class="r-2">
</ul>
</li>
<li>
<a href="#"> menu profondeur1 -c</a>
</li>
</ul>
</li>
<li >
<a href="#"> menu racine -b</a>
<ul class="r-1">
<li class="left-indicator">
<a href="#"> menu profondeur1 -a</a>
<ul class="r-2">
</ul>
</li>
<li>
<a href="#"> menu profondeur1 -b</a>
</li>
<li>
<a href="#"> menu profondeur1 -c</a>
</li>
</ul>
</li>
<li >
<a href="#"> menu racine -c</a>
<ul class="r-1">
<li>
<a href="#"> menu profondeur1 -a</a>
</li>
<li>
<a href="#"> menu profondeur1 -b</a>
</li>
<li>
<a href="#"> menu profondeur1 -c</a>
</li>
</ul>
</li>
</ul>
</div>
Le style de ces blocs <ul> doit contenir le paramètre "list-style-type" affecté à la valeur "none" pour faire disparaitre le point qui normalement précède une liste. Cela est effectué dans chacune des classes r0, r-1, r-2. C'est également dans ces classes que sont paramétrées les marges : margin:0; padding:0;
#menu .r0,
#menu .r-1,
#menu .r-2 {
list-style-type:none;
margin:0;
padding:0;
}
Les listes <ul> autre que les racines (r-1 et r-2) du menu ne doivent pas être affichées lorsque la souris n'est pas sur zone. C'est pourquoi, les classes r-1 et r-2 contiennent le paramètre display avec la valeur none.
Lorsqu'elles seront affichées, il ne faudra pas qu'elles poussent les autres blocs vers le bas d'où le paramètre position avec la valeur absolute qui fixe la place du bloc <ul> sous le dernier bloc positionné (par exemple, l'élément racine du menu <ul class="r0" > pour le menu r-1 ).
#menu .r-1,
#menu .r-2 {
display : none;
position : absolute;
}
Le style li a {} s'applique à tous les liens du menu. L'affichage display:block permet à cet élément inline par défaut d'avoir marge et dimension.
#menu li a {
display:flex;
width:250px;
color:red;
padding:5px;
text-align:center;
Le style a:hover {} colorise les liens du menu au passage de la souris. Ce passage doit également déclencher le cas échant l'affichage du sous-menu. C'est le rôle du paramètre display affecté à la valeur flex des styles li:hover .r-1{} et li:hover .r-1 li:hover .r-2{}. On en profite pour positionner le bloc (flex:auto) et imposer un affichage vertical au sous-menu (flex-direction:column).
#menu li:hover .r-1 {
display: flex;
flex-direction: column;
flex:auto;
margin : 25px 20px;
}
#menu li:hover .r-1 li:hover .r-2 {
display: flex;
flex-direction: column;
flex:auto;
margin : 10px 180px;
}
NB : aide à la lecture du style li:hover .r-1 li:hover .r-2
Une lecture de droite à gauche permet d'en comprendre le fonctionnement. Le style est appliqué sur les balises B de classe r-2 placée à l'intérieur d'un élément <li> survolé par la souris, cet élément doit lui-même être à l'intérieur d'un élément B1 de classe r-1, lui-même à l'intérieur d'un élément <li> survolé par la souris. Cette architecture correspond à la portion de code HTML ci-dessous. A chaque fois que cette séquence se trouve dans le code, le style est appliqué. B1 peut être une balise HTML quelconque, mais dans notre fichier, B1 est la balise <ul>, elle est la seule classée r-1. De même B peut être une balise HTML quelconque, mais dans notre fichier, B est encore la balise <ul>, elle est la seule classée r-2
<li>
...
<B1 classe="r-1">
...
<li>
....
<B classe="r-2">
contenu concerné par le style
</B>
....
</li>....
</B>
....
</li>
Les fichiers
dans le presse papier
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="test2.css">
</head>
<body>
<div id="element1">ce bloc 1 est bleu </div>
<div id="menu" >ce bloc 2 contient le menu
<ul class="r0">
<li>
<a href="#"> menu racine <span class="sub-indicator"> </span></a>
<ul class="r-1">
<li>
<a href="#">menu profondeur1 -a<span class="left-indicator"> </span></a>
<ul class="r-2">
<li>
<a href="#"> menu profondeur2 -a</a>
</li>
<li>
<a href="#"> menu profondeur2 -b</a>
</li>
<li>
<a href="#"> menu profondeur2 -c</a>
</li>
</ul>
</li>
<li >
<a href="#"> menu profondeur1 -b<span class="left-indicator"> </span></a>
<ul class="r-2">
<li>
<a href="#"> menu profondeur2 -a</a>
</li>
<li>
<a href="#"> menu profondeur2 -b</a>
</li>
<li>
<a href="#"> menu profondeur2 -c</a>
</li>
</ul>
</li>
<li>
<a href="#"> menu profondeur1 -c</a>
</li>
</ul>
</li>
<li >
<a href="#"> menu racine -b<span class="sub-indicator"> </span></a>
<ul class="r-1">
<li >
<a href="#"> menu profondeur1 -a<span class="left-indicator"> </span></a>
<ul class="r-2">
<li>
<a href="#"> menu profondeur2 -a</a>
</li>
<li>
<a href="#"> menu profondeur2 -b</a>
</li>
<li>
<a href="#"> menu profondeur2 -c</a>
</li>
</ul>
</li>
<li>
<a href="#"> menu profondeur1 -b</a>
</li>
<li>
<a href="#"> menu profondeur1 -c</a>
</li>
</ul>
</li>
<li >
<a href="#"> menu racine -c<span class="sub-indicator"> </span></a>
<ul class="r-1">
<li>
<a href="#"> menu profondeur1 -a</a>
</li>
<li>
<a href="#"> menu profondeur1 -b</a>
</li>
<li>
<a href="#"> menu profondeur1 -c</a>
</li>
</ul>
</li>
</ul>
</div>
<div id="element2">ce bloc 3 est rouge </div>
</body>
</html>
dans le presse papier
body{
margin:0px auto;
width:90%;
}
#element1 {
background-color:#00CCFF; /* bleu ciel */
}
#element2 {
background-color:#FF6666; /* rouge */
}
#menu {
display:flex;
width:70%;
margin:0px 0px 0px 0px;
background-color:beige;
}
#menu .r0,
#menu .r-1,
#menu .r-2 {
list-style-type:none;
margin:0;
padding:0;
}
#menu .r0 {
display:flex;
flex-direction: row;
margin: 1em 0em 1em 0em;
}
#menu-deroulant .r0 ul {
/* on cache les sous menus complètement sur la gauche */
position: absolute;
left: -999em;
text-align: left;
z-index: 1000;
}
#menu-deroulant .r0 ul li {
display: flex;
flex-direction:column;
}
#menu .r0 > li {
background-color:#b9843f17;
width:240px;
border: solid;
border-width: thin;
border-color: black;
border-radius: 15px 15px 0px 0px;
}
#menu .r-1,
#menu .r-2 {
position : absolute;
left: -999em;
text-align: left;
z-index: 1000;
border: solid;
border-width: thin;
border-color: blue;
background-color:aliceblue;
border-radius: 5px 15px 15px 5px;
}
#menu li {
display:flex;
flex-direction: row;
width:12em;
}
#menu li a {
display:flex;
color:red;
padding:5px;
justify-content: center;
}
#menu li a:hover {
color:#004CFF;
}
#menu .r0 li:hover .r-1 {
display:flex;
flex-direction: column;
margin : 25px 20px;
left:auto;
}
#menu .r0 li:hover .r-1 li:hover .r-2{
display:flex;
flex-direction: column;
margin : 10px 180px;
left:auto;
}
.sub-indicator:after {
content: "▼";
}
.left-indicator:after {
content: "►";
}
Cliquez ici pour afficher ces fichiers dans une fenêtre surgissante
Des onglets et des arrondis
Un toute petite modification (en gras) augmente l'esthétique du menu. On obtient une bordure arrondie pour les sous-menu de niveau 1 et 2.
#menu .r-1,
#menu .r-2 {
position : absolute;
left: -999em;
text-align: left;
background-color:aliceblue;
border: solid;
border-width: thin;
border-color: blue;
border-radius: 5px 15px 15px 5px;
}
Pour arrondir la racine du menu et l'afficher sous forme d'onglets, on modifiera le style .r0 > li {}. Les modifications apportées sont en gras.
#menu .r0 > li {
background-color:#b9843f17;
width:240px;
border: solid;
border-width: thin;
border-color: black;
border-radius: 15px 15px 0px 0px;
}
Un indicateur pour l'existence d'un sous-menu
L'ajout de la classe sub-indicator (resp. left-indicator) comme indiqué dans le code ci-dessous, associé au style .sub-indicator:after (repectivement .left-indicator:after) complète l'ergonomie de l'affichage :
<a href="#"> menu racine <span class="sub-indicator"> </span></a>
<a href="#"> menu profondeur1-a <span class="left-indicator"> </span></a>
.sub-indicator:after {
content: "▼";
}
.left-indicator:after {
content: "►";
}