Niveau Niveau confirmé

Créer un menu déroulant “accordéon” avec jQuery

Tutorieljavascript

Publié par le , mis à jour le (274330 lectures)

menu déroulant javascript jquery accordéon

Le code JavaScript

Le code JavaScript

Intégrer jQuery

La première chose à faire pour pouvoir utiliser jQuery est bien évidemment d'appeller 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, ou bien faites appel à l'URL hébergée par Google API's comme dans les exemples ci-dessous. N'oubliez pas de jeter un coup d'oeil à l'article Inclure jQuery de manière optimisée.

Nous allons insérer l'appel au fichier jQuery :

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>    

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

Note : les exemples ci-dessous se complètent progressivement, ils reprennent à chaque fois l'intégralité du code nécessaire.

Cacher les sous-menus

On veut que les sous-menus soient cachés au chargement de la page, lorsque le visiteur n'a encore actionné aucun élément du menu. Grâce à jQuery et ses sélecteurs utilisant la syntaxe CSS, c'est très simple :

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

<script type="text/javascript">
$(document).ready( function () {
  // On cache les sous-menus :
  $(".navigation ul.subMenu").hide();    
} ) ;
</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é. En exécutant l'instruction au chargement, les éléments ul de classe subMenu sont cachés dynamiquement.

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" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

<script type="text/javascript">
$(document).ready( function () {

    // On cache les sous-menus :
    $(".navigation ul.subMenu").hide();

    // On sélectionne tous les items de liste portant la classe "toggleSubMenu"
    // et on remplace l'élément span qu'ils contiennent par un lien :
    $(".navigation li.toggleSubMenu span").each( function () {
        $(this).replaceWith('<a href="" title="Afficher le sous-menu">' + $(this).text() + '<\/a>') ;
    } ) ;    

} ) ;
</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" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

<script type="text/javascript">
$(document).ready( function () {
    // On cache les sous-menus :
    $(".navigation ul.subMenu").hide();
    // On sélectionne tous les items de liste portant la classe "toggleSubMenu"

    // et on remplace l'élément span qu'ils contiennent par un lien :
    $(".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">' + TexteSpan + '<\/a>') ;
    } ) ;

    // On modifie l'évènement "click" sur les liens dans les items de liste
    // qui portent la classe "toggleSubMenu" :
    $(".navigation li.toggleSubMenu > a").click( function () {
        // Si le sous-menu était déjà ouvert, on le referme :
        if ($(this).next("ul.subMenu:visible").length != 0) {
            $(this).next("ul.subMenu").slideUp("normal");
        }
        // Si le sous-menu est caché, on ferme les autres et on l'affiche :
        else {
            $(".navigation ul.subMenu").slideUp("normal");
            $(this).next("ul.subMenu").slideDown("normal");
        }
        // On empêche le navigateur de suivre le lien :
        return false;
    });    


} ) ;
</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 ...