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.
- [#] Structure de base
- [#] Installation du plugin
- [#] Options
- [#] 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 :
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 detrigger
etcontent
.
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êmeitem
). -
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
});
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'
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
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 classeactive
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. ;)
Merci ! Enfin une explication claire et compréhensible !
Merci beaucoup pour cet exemple simple efficace et clairement expliqué. Un coup de chapeau spécial pour les flèches !
Merci encore
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
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;
}
Bonjour,
Merci beaucoup, ça fonctionne très bien.
Je suis nouveau dans le HTML 5, CSS 3 et le js.
Cordialement,
Jonathan
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.
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 classemax-width
sur ta balise<article class="ui-accordion-item">
, cela devrait fonctionner.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.
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’ ?
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();
Merci beaucoup
Laisser un commentaire