Menus et sous-menus déroulants sans JavaScript

proposé par Gérard, alias lefildargent

Ce tutoriel assez difficile vise à créer un système de menus et sous-menus "déroulants", c'est à dire dans lequel c'est le survol d'un élément de menu qui fait apparaitre le sous-menu correspondant. En voici un exemple :

Oui je sais, esthétiquement ce n'est pas terrible, mais c'est juste pour montrer qu'on peut l'intégrer dans un site Jimdo (nous verrons plus loin comment) même à partir d'un design standard avec un compte free. Survolez le mais évitez de cliquer dans ce menu, ça vous amènerait sur un site de test sans intérêt ici. Au cas où, revenez ici par le bouton page précédente de votre navigateur.

NB : Notes de dernière minute. Explications à l'étude.

Pour que tout ça fonctionne avec IE, il faut au moins la version 8.

Pour que ça marche aussi avec IE 9, j'ai du ajouter ceci dans le bloc head des sources servant dans ce tuto. 

<META content="IE=8.0000" http-equiv="X-UA-Compatible">

mais pas de panique, Jimdo l'a prévu aussi dans sa grande sagesse. 

Démarche générale

L'idée de ce tutoriel est de donner les bases HTML et CSS (sans Javascript) nécéssaires pour réaliser ce menu à 3 niveaux dont le 1er niveau est horizontal et les autres verticaux, et ne se dévoilant qu'au survol de la souris.

Nous allons procéder par étapes depuis cette situation initiale jusqu'à ce rendu.

NB : Le rendu final est très "rustique" mais c'est volontaire pour ne pas tout mélanger. Après il faudrait mettre de la couleur, des fonds, des images, etc ... mais c'est accessoire, ça sort du cadre de ce tuto et vous avez vu plus haut que je n'ai rien à vous apprendre en matière artistique ;) .

On travaille donc complètement hors Jimdo et en quelques lignes on dira à la fin comment l'intégrer dans un site Jimdo.

Références

 

Je ferai parfois référence à "ma bible". Il s'agit du site http://www.w3schools.com/default.asp que je vous recommande.

A chaque étape, un lien ouvrira un nouvel onglet à partir duquel vous pourrez voir le rendu mais aussi récupérer le source. Vous pouvez aussi télécharger ici ce dossier et en extraire tous les sources.
menu.zip
Archives compressées en format ZIP 6.9 KB

La situation initiale : une structure en liste et sous-listes

Comme point de départ, nous prendrons l'arborescence des menus et sous-menus sous forme brute de liste et sous-listes dans un fichier menu00.html

Voici une image du source correspondant : 

Cliquez pour agrandir la vue

Le rendu de ce code est visualisable ici. Il se présente donc sous cette forme : 

Cliquez pour avoir votre propre rendu

Etape 1 : Mises en formes basiques

Il s'agit ici de faire en sorte que les liens correspondant aux menus soient simplement noirs, non soulignés et sans puces pour les listes. Nous allons faire ça en insérant du code CSS dans un bloc style du bloc head du source de notre site.

Ce menu étant destiné à être incorporé dans une page complète contenant éventuellement d'autres listes, on va  intégrer l'ensemble dans une div dédiée avec un identifiant unique (j'ai choisi ici glrmenu).Voici donc un extrait de notre source :

Cliquez pour agrandir la vue

et voici le rendu après cette modification.

Etape 2 : Les sous-listes sont cachées sauf au survol

Allons y doucement, mais surement

Premier essai

On veut ici cacher (en langage CSS display:none) les sous-listes (c'est à dire les listes ul contenues dans un élément de liste li). Mais, lorsque la souris survole l'élément de liste (en langage CSS li:hover), on veut alors que la sous-liste soit visible (en langage CSS display:block). Tout ça ne concerne bien sûr que notre menu identifié glrmenu. Donc on serait tenté par :

div#glrmenu ul li ul {display:none;}
div#glrmenu ul li:hover ul {display:block;}

Soyons fous, essayons ! Ca marche presque sur Firefox, mais pas du tout sur Internet Explorer. Sur IE, en passant la souris sur Jimdo par exemple, rien ne se passe.

Mais pourquoi tant de haine ? Eh bien la réponse est dans la bible ici

Note: In IE there must be declared a  <!DOCTYPE> for the :hover selector to work on other elements than the <a> element.

Autrement dit il faut cette pseudo balise !DOCTYPE au début (avant la balise html). Il serait trop long de préciser ici le pourquoi. Contentons nous de suivre. Disons tout de suite que de toutes façons, toutes les pages Jimdo commencent par

<!DOCTYPE html>

et ça suffira. Notre source est donc devenu :

Cliquez pour agrandir la vue

Voici alors le rendu de notre site.

Observons que si la souris ne survole rien, on n'a que le menu de niveau 1. Si la souris survole l'entrée Jimdo on voit apparaitre le sous-menu de Modifier le design jusqu'à Télécharger Pdf. Par contre le problème en survolant Exemple, c'est que non seulement le sous-menu de niveau 2 apparait, mais aussi le sous-menu de niveau 3.

Deuxième essai

Soyons plus précis et disons qu'après avoir caché toutes les sous-listes, on veut que

  • la sous-liste niveau 2 n'apparaisse qu'au survol de l'élément de liste niveau 1
  • la sous-liste niveau 3 n'apparaisse qu'au survol de l'élément de liste niveau 2.

Pour ça on va qualifier les sous-listes par niveau, c'est à dire leur associer une classe  (attribut class des balises ul). Notre source devient donc

Cliquez pour agrandir la vue

Notez qu'il n'est pas nécessaire ici de qualifier les sous-listes de niveau 3. Toute liste contenue dans un élément d'une liste de niveau 2 est par définition de niveau 3.

Vous pouvez vérifier sur le rendu que tout est normal pour l'instant.

Etape 3 : La liste de niveau 1 horizontale, les autres verticales

Attention, ça devient un peu plus difficile, mais vous êtes chauds, non ?

Niveau 1 horizontal

Pour mettre en horizontal, j'utilise souvent en CSS la propriété display:inline. Mais comme on a déjà "joué" avec display pour cacher ou non les sous-listes, il vaut mieux passer par float:left sur les éléments de liste.  

Donc complétons notre source dans le bloc style du bloc head :

Cliquez pour agrandir la vue

Observez que nous utilisons ici une possibiité particulière du CSS (le signe >) pour faire en sorte que seuls les éléments de liste (li) dépendant directement de la liste de niveau 1 (ul.glrniv1) soient en float:left.

C'est ici dans la bible .

Voici alors le rendu de notre site : Observons.

En observant le rendu on peut voir 2 problèmes :

  • Le sous-menu apparaissant au survol de l'élément de menu père se trouve systématiquement décalé vers la droite.
  • Au survol de la souris si un sous-menu apparait les éléments de menu suivants sont décalés à droite ou vers le bas pour lui laisser la place.

Ajustements

Le premier problème évoqué est facilement réglable en forçant le padding à 0px.

Pour régler le deuxième problème, on va utiliser la propriété position avec la valeur absolute pour toutes les sous-listes de notre menu.

Voici donc notre source ajusté :

Cliquez pour agrandir la vue

Cette propriété position que nous venons d'introduire est parmi les plus difficiles à maitriser en CSS. Par exemple pour la valeur absolute, si on en croit la bible

absolute The element is positioned relative to its first positioned (not static) ancestor element

on pouvait s'attendre à ce que nos sous-listes se retrouvent toutes en haut à gauche de la fenêtre du navigateur puisqu'à ce stade, aucun élément parent n'est positionné. En fait, la place d'un bloc en position:absolute n'est affectée que si on lui applique l'une des propriétés top, left, right ou bottom. Sinon ces propriétés gardent leur valeur (auto) par défaut et le bloc lui-même reste en place.

Voici donc le rendu de notre site avant la dernière étape.

Etape 4 : Décalage à droite du niveau 3

Il y a encore 2 problèmes avec le rendu de notre site :

  • Les éléments de menu de niveau 1 sont collés les uns aux autres. C'est l'effet float:left qui donne ça.
  • Lorsqu'on survole Voyages, le sous-menu correspondant se met par dessus Travail. C'est l'effet position:absolute des sous-listes qui veut ça. 

Là encore le premier problème est facile à régler. Il suffit de forcer une largeur (on va prendre 145 px) pour chaque élément de liste.

Pour le deuxième problème, l'idée est de décaler vers la droite (de 145 px donc) les sous-listes de niveau 3. Pour ça on va utiliser position:relative pour les éléments de liste : ça va avoir comme effet que le positionnement des sous-listes, qui sont elles en position:absolute, va se faire par rapport à l'élément de liste et non plus par rapport au bloc body. Si on s'arrêtait là, ça ne changerait rien. Il faut, en utilisant top et left, mettre en bonne place les sous-listes de niveau 3. Pour ces notions difficiles de positions, je vous conseille aussi ce lien qui a de plus l'intérêt d'être en français.

Ca donne donc pour notre source :

Cliquez pour agrandir la vue

Et voici donc le rendu final de notre exercice. Vous devriez voir ceci

Intégration dans un site Jimdo

Le principe général pour intégrer ce type de menu est de

  • travailler avec des pages cachées et faire vous-même vos menus déroulants
  • copier/coller dans "Paramètres, Modifier le head" ce que nous avons mis dans le bloc head de notre site local
  • copier coller dans un module widget/HTML ce que nous avons mis dans le bloc body de notre site local

C'est en réalité un peu plus compliqué pour diverses raisons : au moins celles-ci.

  • Un côté esthétique : il faudrait de la couleur, des images en background. 
  • La largeur de 145px serait probablement à moduler selon le nombre d'entrée, la police de caractères, etc ...
  • Voir aussi l'avertissement du paragraphe suivant.

Dans le fichier zip proposé en téléchargement au début de ce tuto, vous trouverez :

  • headfinal.html
  • widgetfinal.html 

correspondant au menu déroulant présenté en début de tuto. Il n'est pas beau mais il contient des mises en formes de couleur et d'images.

Avertissement

Si vous êtes curieux et que vous regardez attentivement ce que j'ai mis dans "Paramètres, Modifier le head" du site que vous êtes en train de visualiser, vous allez trouver :

/* Etape 3 : Liste niveau 1 horizontale, sous-listes verticales */
div#glrmenu ul.glrniv1 > li {float:left;}
div#glrmenu li ul {position:absolute;padding:0px;margin:0px;}

Or quand j'ai traité de cette étape 3, j'ai mentionné :

/* Etape 3 : Liste niveau 1 horizontale, sous-listes verticales */
div#glrmenu ul.glrniv1 > li {float:left;}
div#glrmenu li ul {position:absolute;padding:0px;}

Pourquoi cette clause margin dont je n'ai pas parlé ? Et bien amusez-vous avec Firebug par exemple à neutraliser cette clause. Lorsque vous passez la souris sur l'entrée Jimdo, vous allez bien voir le menu de 2ième niveau apparaitre, mais vous ne pourrez pas l'atteindre. Tout ça vient du code CSS que Jimdo intègre sur tous nos sites (free, pro ou business et quelque soit le design Jimdo, spécial ou personnel) par une balise link appelant un fichier ...web.css et qui contient entre autre :

ul,dl,ol {margin-top:0.5em;margin-bottom:0.5em}

Et bien cette marge en haut de chaque liste (balise ul) a comme effet de "désolidariser" l'élément de menu de niveau 1 (Jimdo dans notre exemple) de la liste correspondant au menu de niveau 2. La conséquence est que lorsque la souris passe sur cette marge pour choisir dans son menu de niveau 2, la clause li:hover (que nous avions prévue à l'étape 2) ne s'applique plus et donc ce menu repasse en display:none.