Vous êtes ici : Accueil du blogjQuery » Un menu accordéon (« Accordion effect ») en jQuery

Un menu accordéon (« Accordion effect ») en jQuery

J’ai toujours du mal à faire appel à des solutions comme jQuery UI pour réaliser des effets simples comme la navigation en accordéon. Pourquoi ?

  • Parce que c’est lourd : 19ko de JS dans sa version minifiée quand on ne veut que l’effet accordéon.
  • Parce que ça impose des règles de balisage : le contenu déroulant doit suivre immédiatement le header dans le DOM.
  • Parce que c’est galère à faire évoluer quand on sort des fonctionnalités de base : essayez d’ouvrir plusieurs sections à la fois avec le widget Accordion de jQuery UI.
  • Parce qu’il y a une dépendance des versions et des modules à respecter, au sein même de la librairie, mais aussi entre la librairie et la version de jQuery.

Le plugin accordéon présenté dans cet article s’affranchit des contraintes listées ci-dessus. Il fait le job (plutôt bien), et c’est tout ce qu’on lui demande.

  1. [#] Structure de base
  2. [#] Installation du plugin
  3. [#] Options
  4. [#] Accordéon à section unique : exemple avec une dropdown

Et voici une démo de ce que l’on cherche à obtenir :

Structure de base

Imaginons un menu de navigation à deux niveaux qui aurait la structure suivante :

<ul class="myNav">
	<li class="myNav-item">
		<a class="myNav-link" href="#">Category 1</a>
		<ul class="myNav-content">
			<li><a href="#">Category 1-1</a></li>
			<li><a href="#">Category 1-2</a></li>
			<li><a href="#">Category 1-3</a></li>
		</ul>
	</li>
	<li class="myNav-item">
		<a class="myNav-link" href="#">Category 2</a>
		<ul class="myNav-content">
			<li><a href="#">Category 2-1</a></li>
			<li><a href="#">Category 2-2</a></li>
			<li><a href="#">Category 2-3</a></li>
		</ul>
	</li>
</ul>

Un peu de CSS pour mettre en forme :

.myNav { width:200px; background:#333; }
.myNav-item:not(:first-child) { border-top:1px solid #4d4d4d; }
.myNav-link { display:block; padding:8px 10px; }
.myNav-content { padding:0 20px; padding-bottom:8px; }

Et on obtient quelque chose comme ça :

A noter que le balisage est libre, vous pouvez par exemple utiliser des <div> à la place des <ul> / <li>, et avoir d’avantage de conteneurs pour englober les éléments.

Installation du plugin

On va maintenant ajouter à notre structure les 3 classes CSS qui permettent au script de fonctionner :

  • ui-accordion-trigger sur l’élément qui doit déclencher l’effet,
  • ui-accordion-content sur le contenu à afficher / masquer,
  • ui-accordion-item sur le conteneur des deux éléments précédents
<ul class="myNav">
	<li class="myNav-item ui-accordion-item">
		<a class="myNav-link ui-accordion-trigger" href="#">Category 1</a>
		<ul class="myNav-content ui-accordion-content">
			<li><a href="#">Category 1-1</a></li>
			<li><a href="#">Category 1-2</a></li>
			<li><a href="#">Category 1-3</a></li>
		</ul>
	</li>
	<!-- [...] -->

Même si l’ajout de ces classes peut s’apparenter à des doublons, il est important (pour des raisons de maintenance) de bien différencier les classes à vocation cosmétique de celles dédiées aux comportements JS.

Cependant, une vision composant de l’élément accordéon peut vous amener à réaliser la mise en forme CSS directement sur ces classes ui-. Sachez que si vous souhaitez vous affranchir ou modifier ces classes, c’est possible.

Il nous reste à ajouter dans notre CSS les deux lignes qui permettent de masquer / afficher les contenus :

.ui-accordion-content { display:none; }
.active > .ui-accordion-content { display:block; }

On récupère notre plugin :

DéveloppementMinifié (1ko)

Et on l’initialise dans le <head> ou en bas de page avant </body> :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="js/jquery.simpleAccordion.min.js"></script>
<script>
	$(document).ready(function() {
		$('.myNav').simpleAccordion();
	});
</script>

Le menu accordéon est dorénavant fonctionnel :

Options

Voici toutes les options disponibles et les valeurs par défaut de notre plugin Accordion :

$('.myNav').simpleAccordion({
	item     : '.ui-accordion-item',
	trigger  : '.ui-accordion-trigger',
	content  : '.ui-accordion-content',
	active   : 'active',
	autoclose: false,
	multiple : false,
	speed    : 300
});
  • item (sélecteur) : Classe CSS du conteneur de trigger et content.
    Cet élément est facultatif si votre accordéon ne comporte qu’une seule section (voir rubrique section unique).

  • trigger (sélecteur) : Classe CSS de l’élément permettant de déclencher l’ouverture/fermeture.
    Notez que vous pouvez utiliser plusieurs triggers dans le code HTML (tant qu’ils restent enfants d’un même item).

  • content (sélecteur) : Classe CSS du contenu à afficher/masquer.

    Par exemple en reprenant la structure précédente, on aurait pu s’affranchir des classes .ui- et initialiser l’accordéon de la façon suivante :

    $('.myNav').simpleAccordion({
    	item   : '.myNav-item',
    	trigger: '.myNav-link',
    	content: '.myNav-content'
    });
    
  • active (nom de classe) : Nom de la classe CSS permettant d’identifier une section ouverte.
    On peut utiliser cette classe dans le code HTML pour définir un item initialement ouvert (au chargement de la page) :

    <li class="myNav-item ui-accordion-item active">
  • autoclose (booléen true|false) : Permet de fermer automatiquement les sections de l’accordéon lorsqu’un clique est détecté n’importe où dans la page.
    Cette option est utile lorsqu’il s’agit de mettre en place un effet dropdown.

  • multiple (booléen true|false) : Autorise l’ouverture simultanée de plusieurs sections.

  • speed (entier, en ms) : Permet de modifier la vitesse d’ouverture / fermeture des éléments.

L’exemple suivant combine les options vues précédemment, ainsi que l’ouverture de plusieurs sections au chargement de la page via l’ajout de la classe active :

<ul class="myNav">
	<li class="myNav-item ui-accordion-item active"> ... </li>
	<li class="myNav-item ui-accordion-item active"> ... </li>
	<li class="myNav-item ui-accordion-item active"> ... </li>
</ul>
$('.myNav').simpleAccordion({
	autoclose: true,
	multiple: true,
	speed: 150
});

Accordéon à section unique : exemple avec une dropdown

Des conditions particulières ont été définies dans le script pour simplifier la mise en place d’un accordéon à section unique. Dans ce cas, le conteneur item devient inutile et la classe active est directement appliquée au conteneur global.

Voici un bon exemple d’usage détourné du plugin pour mettre en place une dropdown :

<div class="ui-dropdown">
	<span class="ui-dropdown-trigger">Dropdown</span>
	<div class="ui-dropdown-content">Lorem ipsum dropdown content</div>
</div>
.ui-dropdown { position:relative; }
.ui-dropdown-content { display:none; position:absolute; top:100%; left:0; width:100%; }
.active > .ui-dropdown-content { display:block; }
$('.ui-dropdown').simpleAccordion({
	trigger  : '.ui-dropdown-trigger',
	content  : '.ui-dropdown-content',
	autoclose: true
});
Dropdown
Lorem ipsum dropdown content

Dans cet article je ne fais que survoler tout ce qui touche à la mise en forme CSS des éléments. Si ça intéresse des gens que je rentre dans les détails (flèches de navigation full CSS, rollovers, …), faites-moi signe. ;)

Commentaires (13)

Lâcher un com'

  1. dodo
    04 octobre 2017 à 13h44

    Bonjour !

    Merci pour cet article, il m’a beaucoup aidé !

    J’aimerai savoir comment tu as fait pour mettre les flèches de navigation et les rollovers s’il te plait ?

    merci d’avance,

    Dorine

  2. BeliG
    05 octobre 2017 à 08h24

    Hello Dorine,

    Pour les flèches j’utilise la technique des « triangles CSS », voici des explications sur le sujet ainsi qu’un générateur :
    How CSS triangles work?
    CSS triangle generator

    Pour éviter d’ajouter un élément supplémentaire dans le code HTML, les triangles sont générés via un pseudo élément positionné en absolute.

    Pour gérer le sens de la flèche en fonction de l’état actif / inactif, on joue avec le sélecteur :not et la classe active ajoutée par le script.

    Voici le bout de code qui permet d’arriver au résultat de la démo :

    .myNav-item {
       position:relative; /* Référence aux absolutes */
    }
    .myNav-item:before { /* Flèche */
       content:'';
       position:absolute; top:17px; right:10px;
       width:0; height:0;
       border-style:solid; border-color:transparent;
       border-width:5px; /* Taille de la flèche */
       pointer-events:none; /* Clique neutralisé */
    }
    .myNav-item:not(.active):before { /* Flèche down */
       border-bottom-width:0;
       border-top-color:#fff;
    }
    .myNav-item.active:before { /* Flèche up */
       border-top-width:0;
       border-bottom-color:#fff;
    }
    .myNav-item.active,
    .myNav-item:hover {
       background:#404040; /* État actif et rollover */
    }

    N’hésite pas si tu as d’autres questions. ;)

  3. Chadev
    19 février 2018 à 10h33

    Merci ! Enfin une explication claire et compréhensible !

  4. Loic MONET
    22 juin 2018 à 14h25

    Merci beaucoup pour cet exemple simple efficace et clairement expliqué. Un coup de chapeau spécial pour les flèches !
    Merci encore

  5. Jonathan
    28 juin 2019 à 09h24

    Bonjour,
    je suis entrain de tester le menu accordéon et je voulais savoir si il est possible de jouer ave les class i font Awesome entre + -.

    Si vous avez une solution.

    Merci d’avance,
    Jonathan

  6. BeliG
    28 juin 2019 à 11h13

    Bonjour Jonathan,

    C’est tout à fait possible d’utiliser font Awesome pour les éléments de navigation, et de faire varier les pictos en fonction de l’état ouvert/fermé de l’accordéon.

    Voici une première solution full CSS basée sur l’utilisation du pseudo-élément :before :

    /* Icônes base */
    .myNav-link:before {
       font-family: 'Font Awesome 5 Free'; /*(1)*/
       font-weight: 900; /*(2)*/
       display: inline-block; /*(3)*/
    }

    /* Icône état fermé */
    .myNav-item:not(.active) .myNav-link:before {
       content: '\f067'; /*(4)*/
    }

    /* Icône état ouvert */
    .myNav-item.active .myNav-link:before {
       content: '\f068'; /*(4)*/
    }

    (1) Le nom de la font qui dépend de la version que tu utilises. Si tu utilises la dernière version il existe 2 fonts différentes :
    "Font Awesome 5 Free" (pour les icônes "Regular" et "Solid")
    "Font Awesome 5 Brand" (pour les icônes "Brands")

    (2) La graisse qui dépend du type des pictos utilisés :
    "300" pour "Light"
    "400" pour "Regular" et "Brands"
    "900" pour "Solid" (type des pictos "+" et "-")

    (3) Styles additionnels pour la mise en forme (taille, alignement, espacement, ...)

    (4) Les "codes pictos" que tu pourras retrouver dans la doc :
    https://fontawesome.com/icons/plus?style=solid
    https://fontawesome.com/icons/minus?style=solid

    Une deuxième solution consiste à ajouter les deux balises i et de jouer avec les états actif/inactif pour l'affichage (c'est plus simple mais moins propre que la solution précédente, notamment en terme d'accessibilité et de maintenance) :

    HTML
    <a href="#" class="myNav-link ui-accordion-trigger">
       <i class="myNav-icon fas fa-plus"></i>
       <i class="myNav-icon fas fa-minus"></i>
       Rubrique
    </a>

    CSS
    /* Fermé, on masque le "-" */
    /* Ouvert, on masque le "+" */
    .myNav-item:not(.active) .myNav-icon.fa-minus,
    .myNav-item.active .myNav-icon.fa-plus {
       display: none;
    }

  7. Jodar
    01 juillet 2019 à 08h21

    Bonjour,

    Merci beaucoup, ça fonctionne très bien.

    Je suis nouveau dans le HTML 5, CSS 3 et le js.

    Cordialement,
    Jonathan

  8. Rémy
    01 novembre 2019 à 17h03

    Bonjour,

    Tout d’abord merci pour votre travail.
    Je viens d’installer votre script « simpleAccordion », tout fonctionne à part la notion de ‘multiOpen’.
    J’ai l’impression d’avoir raté qq-chose…
    Si vous voulez jeter un œil : https://www.senouillac.fr/vos-demarches.html

    Cordialement,
    Rémy.

  9. BeliG
    01 novembre 2019 à 18h21

    Bonjour Rémy,

    Je vois où se situe le problème. Le script cherche à refermer les « frères » de l’élément cliqué, via la méthode siblings().
    Or dans ton cas les éléments à refermer ne sont pas des « frères » mais des « cousins », parce que tous les <article class="ui-accordion-item"> ont une div parente <div class="max-width">.

    En attendant que je mette à jour le script pour éviter ce problème, as-tu la main sur le code de ton site ?

    Si tu supprimes toutes tes <div class="max-width"> et que tu déplaces la classe max-width sur ta balise <article class="ui-accordion-item">, cela devrait fonctionner.

  10. Rémy
    03 novembre 2019 à 11h18

    Bonjour Mathieu,
    Parfait, ça fonctionne !
    Du coup j’en ai profité pour faire un peu connaissance avec la méthode siblings, fabuleuse méthode…
    Merci à toi !
    Bon Week-End,
    Rémy.

  11. Ademus
    08 janvier 2020 à 16h20

    Bonjour,

    Est il possible à partir du script de cet accordeon, d’avoir un accordéon ‘récursif’, c a d, avec plusieurs niveaux imbriqués qui fonctionnent tous en mode ‘accordéon’ ?

  12. BeliG
    08 janvier 2020 à 18h13

    Bonjour Ademus,

    Il est possible d’imbriquer les accordéons à l’infini, si j’ai bien compris ta question.

    J’ai prévu d’ajouter des démos sur le sujet, en attendant voici deux exemples pour te donner une idée :

    1. Initialisation spécifique de chaque accordéon

    myNav
      myNav-item ui-accordion-item
        myNav-link ui-accordion-trigger
        myNav-content ui-accordion-content
          mySubNav
            mySubNav-item ui-accordion-item
              mySubNav-link ui-accordion-trigger
              mySubNav-content ui-accordion-content
                [...]

    Cette structure permet d’initialiser les accordéons avec des paramètres spécifiques :

    $('.myNav').simpleAccordion();
    $('.mySubNav').simpleAccordion();

    2. Initialisation globale

    myNav ui-accordion
      myNav-item ui-accordion-item
        myNav-link ui-accordion-trigger
        myNav-content ui-accordion-content
          mySubNav ui-accordion
            mySubNav-item ui-accordion-item
              mySubNav-link ui-accordion-trigger
              mySubNav-content ui-accordion-content
                [...]

    On initialise globalement tous les accordéons avec les mêmes paramètres :

    $('.ui-accordion').simpleAccordion();

  13. Mat
    06 juillet 2021 à 07h18

    Merci beaucoup

Laisser un commentaire

Balises HTML autorisées dans la rédaction du message :
<strong> <a> <code> <q>

Les champs marqués d'une étoile sont obligatoires.

Current month ye@r day *