Aller au contenu principal


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.

Dernière MAJ :
06 oct 2023
Billet créé le :
18 nov 2020

Cliquer pour agrandir l'image

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;  
}

Il est possible, comme c'est le cas dans le fichier CSS de l'onglet ci-dessous, d'utiliser le paramètre flex en remplacement de display, à condition de lui affecter une valeur qui place le bloc hors d'une zone affichable (par exemple -999em).

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

Cliquez sur le bouton pour copier le code
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>                       

                                

Cliquez sur le bouton pour copier le code
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: "►";  
}

Attention cependant à faire figurer la section <meta charset="UTF-8"> dans la balise <head> de votre code <html>pour permettre cet affichage.