Créer un menu « accordéon » avec jQuery

Écrit par aDy. Posté dans Tutos jQuery

Vous avez aimé cet article ? Apportez votre petit « plus » ci-dessous !

Voici un superbe tutorial proposé par Thomas Dedericks de chez AlsaCreations pour vous permettre de créer un menu de type accordéon en JavaScript à l’aide de jQuery ^^

Exemple d'un menu accordéon

Exemple d

Introduction

Le but de ce tutoriel est de transformer le menu HTML du chapitre suivant en un menu « accordéon ». Un menu « accordéon » est un menu déroulant un peu particulier, dont les sous-menus s’ouvrent au clic de souris (ou au focus).
Pour cela, on va bien sûr utiliser JavaScript, mais en se basant sur la bibliothèque jQuery. J’ai utilisé la version 1.2.1 de jQuery, la plus récente au moment d’écrire ces lignes.

Pour plus de renseignements sur le fonctionnement et les possibilités offertes par jQuery, je vous invite à consulter la documentation en ligne, très utile (mais uniquement en anglais).

Le code HTML : Structure (X)HTML

Voici le code de base du menu :

<ul class="navigation">
        <li><a title="Aller à la page 1" href="#">Item 1</a></li>
        <li class="toggleSubMenu"><span>Item 2</span>
<ul class="subMenu">
        <li><a title="Aller à la page 2.1" href="#">Item 2.1</a></li>
        <li><a title="Aller à la page 2.2" href="#">Item 2.2</a></li>
        <li><a title="Aller à la page 2.3" href="#">Item 2.3</a></li>
</ul>
</li>
        <li class="toggleSubMenu"><span>Item 3</span>
<ul class="subMenu">
        <li><a title="Aller à la page 3.1" href="#">Item 3.1</a></li>
        <li><a title="Aller à la page 3.2" href="#">Item 3.2</a></li>
</ul>
</li>
        <li><a title="Aller à la page 4" href="#">Item 4</a></li>
</ul>

qu’il faudra bien sûr insérer dans une page HTML complète (par exemple, une page générée par Squelettor).

Remarquez la présence des éléments span dans les éléments de liste qui contiennent des sous-menus, ainsi que les classes utilisées sur ces mêmes éléments et les sous-menus.

Images employées

Les images employées pour ce tutoriels sont celles-ci :

Item de menu par défaut

Item de menu par défaut

Item de menu enroulé

Item de menu enroulé

Item de menu déroulé

Item de menu déroulé

Vous pouvez bien évidemment employer vos propres images, voire ne pas en utiliser du tout et vous contenter des styles CSS.

Le code JavaScript : Intégrer jQuery

La première chose à faire pour pouvoir utiliser jQuery est bien évidemment d’appeler la librairie dans la page. Téléchargez jQuery sur le site officiel, et placez-le dans le répertoire (ou dans un sous-répertoire) où vous avez enregistré le fichier HTML.

Nous allons insérer l’appel au fichier jQuery dans la balise head, comme décrit dans ce point de la FAQ :

<script src="jquery-1.2.1.js" type="text/javascript"><!--mce:0--></script>

Dorénavant, on peut accéder aux méthodes de la bibliothèque jQuery dans tout le reste de la page.

Cacher les sous-menus
<script type="text/javascript"><!--mce:1--></script>

On aurait évidemment pu cacher les sous-menus en appliquant la propriété CSS display: none, mais cette façon de faire rend le menu inutilisable pour les utilisateurs qui ne disposent pas de JavaScript ou qui l’ont désactivé.

Transformer les span en liens

Il est possible de faire réagir les éléments de liste au clic pour faire apparaître les sous-menus, comme n’importe quel élément HTML. Le problème est que les éléments de liste ne captent pas le focus lorsque l’utilisateur navigue au clavier, contrairement aux liens.

Evidemment, on pourrait utiliser directement un lien, avec un attribut href vide. Mais dans ce cas, on se retrouve avec un lien inutile si JavaScript est désactivé.

Pour obtenir un résultat aussi accessible et ergonomique que possible (pour un menu déroulant), j’ai choisi de générer des liens à l’aide de JavaScript. Ainsi, le code HTML reste propre et le menu devient utilisable au clavier.

<script type="text/javascript"><!--mce:2--></script>
Gérer l’affichage des sous-menus

Il faut maintenant que les sous-menus se déroulent lorsque l’on clique sur les liens. On va utiliser un des effets graphique fournis par jQuery, via la fonction slideToggle, qui fera apparaitre/disparaitre les sous-menus en augmentant/reduisant progressivement leur hauteur.

Il y a deux cas de figure qui peuvent se présenter lorsque l’utilisateur clique sur un lien :

  • soit le sous-menu correspondant est ouvert, et on doit simplement le replier ;
  • soit le sous-menu est fermé. Dans ce cas, il faut afficher le sous-menu correspondant et fermer les autres sous-menus.

Il n’est pas difficile de réaliser qu’en procédant de cette manière, il n’y aura jamais plus d’un seul sous-menu affiché, puisqu’à chaque fois qu’on en ouvre un, on referme les autres ! Combinée avec les effets de « slideUp » et « slideDown », cette méthode donnera l’effet « d’accordéon » recherché.

Voici le code modifié :

<script type="text/javascript"><!--mce:3--></script>

Plusieurs points intéressants à creuser ici, et notamment :

Et voilà, le menu est d’ores et déjà fonctionnel ! Mais il est encore largement perfectible …

Les styles CSS

Pour commencer, nous allons utiliser les styles CSS pour rendre le menu un peu plus sexy. Voici les styles utilisés dans l’exemple :

   .navigation {
      margin: 0;
      padding: 0;
      list-style: none;
      background: #000;
      color: #fff;
      width: 200px;
      font: 1.2em "Trebuchet MS", sans-serif;
      }
   .navigation a, .navigation span {
      display: block;
      padding: 4px 10px;
      color: #fff;
      text-decoration: none;
      background: #000 url(menu-item.png) left bottom no-repeat;
      }
   .navigation .toggleSubMenu a, .navigation .toggleSubMenu span {
      background-image: url(menu-item-deroule.png);
      }
   .navigation .open a, .navigation .open span {
      background-image: url(menu-item-enroule.png);
      }
   .navigation a:hover, .navigation a:focus, .navigation a:active {
      text-decoration: underline;
      }
   .navigation .subMenu {
      font-size: .8em;
      background: #ccc url(subMenu.png) 0 0 repeat-x;
      font-size: .9em;
      margin: 0;
      padding: 0;
      border-bottom: 1px solid #666;
      }
   .navigation ul.subMenu a {
      background: none;
      padding: 3px 20px;
      }

Hop, c’est déjà nettement plus agréable à regarder, pas vrai ? Évidemment, il reste quelques bugs à corriger sous IE6 et consorts, mais ce n’est pas l’objet de ce tutoriel … débrouillez-vous ;)

Et si vous voulez savoir à quoi sert la classe "open", continuez à lire !

Améliorer l’ergonomie : Marquer les éléments « déclencheurs »

Pour améliorer l’ergonomie du menu, on va faire en sorte de distinguer les liens qui déclenchent le déroulement d’un sous-menu des autres. Et dans la foulée, on va aussi distinguer ceux qui permettent de cacher un sous-menu.

Pour cela, il nous suffit d’ajouter une classe aux éléments de liste dans lesquels il y a un sous-menu ouvert. On pourra en effet modifier l’apparence de cet élément à l’aide des styles. Les autres éléments contenant un sous-menu sont déjà connus, ils portent tous la classe toggleSubMenu !

Donc, en résumé, lorsqu’on ouvre le sous-menu, il faut ajouter une classe (par exemple « open »), et lorsqu’on le referme, il faut la supprimer. Il faudra aussi supprimer cette classe si elle existe pour un autre sous-menu.

jQuery possède deux méthodes, addClass() et removeClass(), qui vont faire la majorité du travail à notre place :

<script type="text/javascript"><!--mce:4--></script>

Il suffit maintenant de styler li.open et li.toggleSubMenu différemment grâce aux CSS.

Garder un sous-menu ouvert

Lorsque le visiteur clique sur un des « vrais » liens du menu, il est normalement envoyé sur une autre page. Résultat, la page est rechargée, et le sous-menu dans lequel l’utilisateur naviguait n’apparait plus, il a été fermé.

Il est possible de le garder ouvert après un changement de page, mais on va avoir besoin d’intervenir directement sur le code HTML.

Si votre site est statique, il suffit d’ajouter à la main une classe (par exemple « open_at_load ») sur le sous-menu que vous voulez garder ouvert (en fonction de la page). Pour les sites dynamiques, il est aussi possible de générer cette classe, en fonction d’une variable $_GET['page'] ou autre.

Dès lors, il suffit de dire au script de fermer tous les sous-menus au chargement, sauf celui qui porte la classe « open_at_load » :

<script type="text/javascript"><!--mce:5--></script>
Conclusion

Le menu n’est pas vraiment terminé. Il reste quelques améliorations faciles à apporter, notamment en utilisant la méthode des portes coulissantes pour les effets de survol CSS au lieu d’images séparées (ou en préchargeant les images via JavaScript). Mais vous trouverez les techniques nécessaires dans d’autre tutoriaux, et pas très loin d’ici.

Récapitulons : nous avons réalisé un menu accordéon qui fonctionne avec les principaux navigateurs du marché, qui reste accessible et logique si JavaScript est désactivé, et utilisable au clavier. Le tout avec, si je compte bien, une vingtaine de lignes de code JavaScript. Pas mal !

La bibliothèque jQuery offre bien d’autres possibilités. Je vous invite à explorer un peu son fonctionnement, en changeant l’effet utilisé pour afficher les sous-menus, la vitesse, etc. Amusez-vous …

Le principal inconvénient des bibliothèques JavaScript est (était ?) leur poids souvent excessif. À vous de voir si les 27 ko de jQuery valent la peine ou pas …

Remerciement

Un grand merci à Thomas Dedericks qui a rédigé ce superbe tutoriel ;)

Mots-clefs : , , , ,

Rétrolien depuis votre site.

Commentaires (12)

  • Sophie

    |

    Merci pour ce tutoriel mais il y a qqchose qui me chiffone. Je ne comprends pas pourquoi changer la balise span pour en faire un lien qui ne pointe sur rien.
    Ou est l’intéret?
    Si on supprime cette partie ci du code:

    $(".navigation li.toggleSubMenu span").each( function () {
            // On stocke le contenu du span :
            var TexteSpan = $(this).text();
            $(this).replaceWith('<a href="" title="Afficher le sous-menu" rel="nofollow">' + TexteSpan + '</a>') ;
        } ) ;

    Et que on remplace celle-ci:

    $(".navigation li.toggleSubMenu > a").click( function () {

    par

    $(".navigation li.toggleSubMenu > span").click( function () {

    Ca fonctionne aussi bien alors pourquoi transformer ce span en balise href? :getlost:

    Répondre

  • aDy

    |

    Coucou Sophie !

    En fait la balise span est un simple conteneur (comparable à la balise DIV) qui ici, est moins adapté pour cliquer et afficher donc le sous-menu.
    Tu remarqueras que ici le lien possède un attribut « title » qui n’est pas compatible avec la balise span.
    Enfin je ne suis pas certain que l’attribut rel= »nofollow » soit indispensable ici vu que le lien ne pointe nulle part.
    Hésite pas si tu as d’autres questions ;)

    Répondre

  • Ronan

    |

    Bonjour, et merci pour le partage de tuto ! Je me suis servi de ce tuto pour réaliser un menu. Jusque là tout va bien tout fonctionne… mais, car oui il y a un mais, je souhaiterai faire des sous-sous-menu, malheuresement ça ne fonctionne pas, ou alors je m’y prends mal, aurais-tu quelques minutes à m’accorder pour m’aider ?

    Merci par avance.

    Cordialement,
    Ronan.

    Répondre

  • SKIBINSKI freddy

    |

    Bonjour, et merci pour cet excellent tuto

    J’ai juste un problème pour la classe « open_at_load ». Je ne sais pas où la placer dans le code HTML dans la page appelée pour que le sous-menu reste ouvert

    merci de m’nvoyer le code HTML pour la classe « open_at_load ».

    Cdlt

    freddy.

    Répondre

  • Ivy

    |

    Bonjour,

    J’ai exactement le même soucis que Freddy en ce qui concerne le open_at_load. Pourriez vous me donner le code HTML pour cette classe open_at_load

    Merci

    Ivy

    Répondre

  • djcoyotte

    |

    Pour rajouter une class sur un menu static (c’est à dire qui est present sur toutes tes pages html) rien de plus simple :

    voici un exemple de menu :

    <a href="#none" rel="nofollow">rubrique 1</a>
    <a href="#" rel="nofollow">blablabbla</a>
    <a href="#" rel="nofollow">Les missions et bénéficiaires</a>
    <a href="#" rel="nofollow">L'offre de service</a>
     
    <a href="#none" rel="nofollow">rubrique 2</a>
    <a href="#" rel="nofollow">Informations</a>
    <a href="#" rel="nofollow">Témoignages</a>
    <a href="#" rel="nofollow">Formations</a>

    Si tu veut que le sous menu de la RUBRIQUE 1 reste ouvert tu rajoute la class open_at_load au SUBMENU:

    <a href="#none" rel="nofollow">rubrique 1</a>

    si tu veut que se soit pour la rubique deux meme principe en prenant soin d’effacer le open_at_load sur la rubrique 1 sinon tes deux menu resteront ouvert…:

    <a href="#none" rel="nofollow">rubrique 2</a>

    voila j’espère que j’ai pu aider certain d’entre vous…

    Par contre moi j’ai un autre souci puisque mon menu est gérer dynamiquement. c’est à dire que j’ai une page index.php avec mon menu et d’autreS pageS injecter sur mon « index » par un include… mon souci c’est de créer une variable qui se sur chacune de mes pages (ex: ) et de la recuperer sur mon menu (ex: ) mais cela ne fonctionne pas…

    Quelqu’un peut-il m’éclairer?
    Merci d’avance !

    Répondre

  • djcoyotte

    |

    mince toute mes excuses j’ai oublier de mettre en code… quelqu’un peut-il modifier ca?

    Répondre

  • aDy

    |

    C’est fait !
    Merci de ta contribution ;)

    Répondre

  • rais

    |

    merci infiniment pour votre aide c est genial ca me plais je veux l appliquer dans mon site que je viens de creer : a bien tot.

    Répondre

  • Adrien

    |

    Avec plaisir rais ! :)

    Répondre

  • Rakoto

    |

    Bonjour,
    quelqu’un pourrait me montrer comment remplacer le texte Page 2 par exemple par un image?

    Répondre

Laisser un commentaire

Ce site utilise KeywordLuv, pour en profiter : Entrez VotreNom@VotreMotClé dans le champ Nom.
Merci d'être constructif, d'éviter les messages trop courts et sur-optimisés sous peine de ne pas être publiés.

This Blog will give regular Commentators DoFollow Status. Implemented from IT Blögg