Wow, c’est pas croyable, j’écrivais mon premier tutoriel il y a 25 ans, un mercredi 12 novembre 1997! Un quart de siècle plus tard, Les Trucsweb sont toujours là...
Nous verrons donc dans ce tutoriel comment faire un menu avec un bouton de type « hamburger » animé et compatible Bootstrap v5.3.0. C’est un truc courant, mais il n’existe pas vraiment d’exemple avec un menu de type « offcanvas ». La différence est notable, le menu conventionnel de Bootstrap change la classe dans le conteneur du menu (et du bouton hamburger), il est donc possible de cibler directement l’étant du menu en CSS pure! Mais pas avec le menu de type « offcanvas ». En effet, celui-ci change l’état du menu directement dans la fenêtre « offcanvas » ce qui ne permet plus de ciller bouton uniquement en CSS. Il faut utiliser un JavaScript pour détecter les états du menu et ajuster le bouton « hamburger » en conséquence.
En prime, étant donné que la particularité de Bootstrap v5.3.0 et les « modes de couleur », l’exemple prendra en charge cette nouvelle fonctionnalité du célèbre cadriciel Bootstrap en offrant un support pour le mode clair et le mode foncé.
Ce qu’il y a d’intéressant avec ce tutoriel, c’est qu’il couvre plusieurs techniques CSS. Dont la transition CSS pour un effet fluide et la transformation CSS 2D pour appliquer une rotation.
- Transition CSS
- Transformation 2D
- Le bouton « hamburger »
- Barre de menu Boostrap 5
- Menu « offcanvas » Bootstrap 5
Transition et transformation CSS
La transition
La transition CSS est un outil puissant qui permet de changer graduellement dans le temps, une ou plusieurs propriétés d’un élément. Il suffit de spécifier la propriété et la durée en seconde (s) ou en milliseconde (ms).
:hover
Exemple avec la couleur de fond background-color
:
<style>
.btn-test1 {
background-color: yellow;
transition: background-color 12s;
}
.btn-test1:hover {
background-color: red;
}
</style>
<button class="btn-test1">Passer la souris</button>
<style>
.btn-test2 {
color: black;
background-color: yellow;
transition: background-color 12s, color 12s;
}
.btn-test1:hover {
color: white;
background-color: red;
}
</style>
<button class="btn-test2">Passer la souris</button>
La couleur de fond jaune tourne au rouge ET la couleur noire tourne au blanc graduellement en 12 secondes.
La transition all
Ou encore, utiliser all
pour cibler toutes les propriétés. Dans ce cas-ci, tant la couleur que la couleur de fond :
<style>
.btn-test3 {
color: black;
background-color: yellow;
transition: all 12s;
}
.btn-test3:hover {
color: white;
background-color: red;
}
</style>
<button class="btn-test3">Passer la souris</button>
La propriété transition-timing-function
La propriété transition-timing-function
spécifie la « courbe » de vitesse de l’effet de transition. C’est-à-dire quelle module la transition en fonction du début et de la fin de la transition.
La propriété transition-timing-function peut avoir 6 valeurs :
ease
- spécifie un effet de transition avec un démarrage lent, puis rapide, puis se termine lentement (par défaut) ;linear
- spécifie un effet de transition avec la même vitesse du début à la fin ;ease-in
- spécifie un effet de transition avec un démarrage lent ;ease-out
- spécifie un effet de transition avec une fin lente ;ease-in-out
- spécifie un effet de transition avec un début et une fin lents ;cubic-bezier(n,n,n,n)
- vous permet de définir vos propres valeurs dans une fonction « cubic-bezier ».
Par défaut, les exemples précédents on une « courbe » ease
, soit lent => rapide => lent. Voici le même exemple avec la valeur linear
:
<style>
.btn-test4 {
color: black;
background-color: yellow;
transition: all 12s linear;
}
.btn-test3:hover {
color: white;
background-color: red;
}
</style>
<button class="btn-test4">Passer la souris</button>
Javascript
Et pourquoi pas en JavaScript pour plus de flexibilité, cette fois un ciblant un click
. On peut alors manipuler notre élément en JavaScript, directement sur une propriété ou en changeant de classe comme l’exemple suivant :
<style>
.btn-test5 {
color: black;
background-color: yellow;
transition: all 12s linear;
}
.btn-test5-anime {
color: white;
background-color: red;
}
</style>
<button class="btn-test5">Cliquer</button>
<script>
const oBtntest5 = document.querySelector(".btn-test5")
oBtntest5.addEventListener("click", function() {
this.classList.toggle('btn-test5-anime');
});
</script>
La transformation (transform)
Une transformation 2D ou 3D de l’élément HTML. Exemple avec une rotation à 45 degrés :
<style>
.btn-test6 {
color: black;
background-color: yellow;
transition: all 0.2s;
transform: rotate(0);
}
.btn-test6-anime {
color: white;
background-color: red;
transform: rotate(45deg);
}
</style>
<button class="btn-test6">Cliquer</button>
<script>
const oBtntest6 = document.querySelector(".btn-test6");
oBtntest6.addEventListener("click", function() {
this.classList.toggle('btn-test6-anime');
});
</script>
Passons aux choses sérieuses en abordant le fameux bouton « hamburger », c’est-à-dire les trois minces lignes .
Le bouton « hamburger »
Il existe une infinité de transformations pour le bouton hamburger, avec plus ou moins d’effet. La plus simple c’est de ne rien faire, il suffit alors d’un caractère ☰ ou d’un pictogramme , exactement comme l’exemple de Bootstrap. Mais pour animer les trois barres indépendamment les uns des autres, il faut trois éléments distincts. Celle du haut, celle du milieu et celle du bas.
<style>
button {
border:none;
padding:8px
}
.barres {
width: 21px;
height: 2px;
background-color: #000000;
display: block;
transition: all 0.2s;
}
.barre-millieu8 {
margin: 4px auto;
}
</style>
<button>
<span class="barres"></span>
<span class="barres barre-millieu8"></span>
<span class="barres"></span>
</button>
Trois lignes 2 pixels d’épais avec une marge de 4px sur celle du milieu. Reste à l’animer maintenant !
<style>
button {
border:none;
padding:8px
}
.barres {
width: 21px;
height: 2px;
background-color: #000000;
display: block;
transition: all 0.2s;
}
.barre-millieu8 {
margin: 4px auto;
}
/* Menu ouvert */
.btn-test8 .barre-haut {
transform: rotate(45deg);
transform-origin: 10% 10%;
}
.btn-test8 .barre-millieu8 {
opacity: 0;filter: alpha(opacity=0);
}
.btn-test8 .barre-bas {
transform: rotate(-45deg);
transform-origin: 10% 90%;
}
/* Menuy fermer */
.btn-test8.fermer .barre-haut {
transform: rotate(0);
}
.btn-test8.fermer .barre-millieu8 {
opacity: 1;filter: alpha(opacity=100);
}
.btn-test8.fermer .barre-bas {
transform: rotate(0);
}
</style>
<button class="btn-test8 fermer">
<span class="barres barre-haut"></span>
<span class="barres barre-millieu8"></span>
<span class="barres barre-bas"></span>
</button>
<script>
const oBtntest8 = document.querySelector(".btn-test8")
oBtntest8.addEventListener("click", function() {
this.classList.toggle('fermer');
});
</script>
Résultat :
Barre de menu Boostrap 5
Ce qui est très pratique avec la barre de menu Bootstrap 5 c’est que le bouton hamburger fonctionne en pure CSS sans une ligne de JavaScript supplémentaire. Parce qu’on peut exploiter la façon dont fonctionne ce menu. Bootstrap change l’état du menu version bureau à version cachée pour mobile en ajoutant la classe collapsed
au conteneur navbar-toggle
. Le JavaScript est déjà inclus dans les scripts Bootstrap. Alors il suffit de cibler la classe navbar-toggle
pour animer notre bouton.
Donc vous réutilisez simplement le code CSS de l’exemple précédent, et il suffit de remplacer le bouton Bootstrap original par celui-ci :
<button class="navbar-toggler collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#oMenuPrincipal" aria-controls="oMenuPrincipal" aria-expanded="false" aria-label="Navigation">
<span class="barres barre-haut"></span>
<span class="barres barre-millieu3"></span>
<span class="barres barre-bas"></span>
</button>
Assurez-vous que la class collapsed
est par défaut. Et remplacer le pictogramme par les trois barres.
L’exemple suivant inclut le code complet avec deux variables par thème « dark » et « light » de Boostrap. Une couleur --tw-ham-color
et une couleur de fons --tw-ham-active-color
. Vous devez utiliser l’exemple de Bootstrap pour le faire fonctionner.
<style>
/* Près pour la gestion de thème Bootstrap v5.3.0 */
[data-bs-theme="dark"] {
--tw-ham-color: var(--bs-gray);
--tw-ham-active-color: var(--bs-gray);
}
[data-bs-theme="light"] {
--tw-ham-color: var(--bs-gray);
--tw-ham-active-color: var(--bs-gray);
}
/* Retire la bordure et le « outline » autour du bouton Bootstrap */
.navbar-toggler {
border: 0 !important;
}
.navbar-toggler:focus,
.navbar-toggler:active,
.navbar-toggler-icon:focus {
outline: none !important;
box-shadow: none !important;
border: 0 !important;
}
.barres {
width: 21px;
height: 2px;
background-color: var(--tw-ham-color);
display: block;transition: all 0.2s;
}
.barre-millieu3{
margin: 4px auto;
}
/* Menu ouvert */
.navbar-toggler .barre-haut {
transform: rotate(45deg);
transform-origin: 10% 10%;
}
.navbar-toggler .barre-millieu3 {
opacity: 0;
filter: alpha(opacity=0);
}
.navbar-toggler .barre-bas {
transform: rotate(-45deg);
transform-origin: 10% 90%;
}
/* Menu Fermer */
.navbar-toggler.collapsed .barre-haut {
transform: rotate(0);
}
.navbar-toggler.collapsed .barre-millieu3 {
opacity: 1;
filter: alpha(opacity=100);
}
.navbar-toggler.collapsed .barre-bas {
transform: rotate(0);
}
.navbar-toggler.collapsed .barres {
background-color: var(--tw-ham-active-color);
}
</style>
<!-- exemple sombre -->
<body data-bs-theme="dark">
<!-- exemple clair -->
<body data-bs-theme="light">
<nav class="navbar navbar-expand-lg bg-body">
<div class="container-fluid">
<a class="navbar-brand" href="#">Trucsweb.com</a>
<button class="navbar-toggler collapsed" type="button" data-bs-toggle="collapse"
data-bs-target="#oMenuPrincipal" aria-controls="oMenuPrincipal" aria-expanded="false" aria-label="Navigation">
<span class="barres barre-haut"></span>
<span class="barres barre-millieu3"></span>
<span class="barres barre-bas"></span>
</button>
<div class="collapse navbar-collapse" id="oMenuPrincipal">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">À propos</a>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Recherche" aria-label="Recherche">
<button class="btn btn-outline-success" type="submit">Recherche</button>
</form>
</div>
</div>
</nav>
Résultat : Exemple du menu « offcanvas » avec bouton « Hamburger » animé
Menu « offcanvas » Bootstrap 5
Le menu « offcanvas » de Bootstrap ne fonctionne pas de la même manière. Il n’ajoute pas la classe collapsed
au conteneur navbar-toggler
. En fait, pour faire une histoire courte, il ajoute la classe show
au conteneur de l’« offcanvas » quand il est colplètement ouvert. Il faut donc gérer le bouton en JavaScript. À partir d’ici, toutes les solutions sont bonnes. Personnellement, je détecte l’ouverture et la fermeture de l’« offcanvas » pour ajouter ou supprimer la classe collapsed
moi même.
C’est exactement le même code CSS :
/* Près pour la gestion de thème Bootstrap v5.3.0 */
[data-bs-theme="dark"] {
--tw-ham-color: var(--bs-gray);
--tw-ham-active-color: var(--bs-gray);
--tw-offcanvas: var(--bs-white);
--tw-offcanvas-color: var(--bs-dark);
--tw-offcanvas-active-color: var(--bs-gray);
}
[data-bs-theme="light"] {
--tw-ham-color: var(--bs-gray);
--tw-ham-active-color: var(--bs-gray);
--tw-offcanvas: var(--bs-dark);
--tw-offcanvas-color: var(--bs-white);
--tw-offcanvas-active-color: var(--bs-gray);
}
/* Couleurs de l’offcanvas */
#oMenuMobile {
background-color:var(--tw-offcanvas);
color:var(--tw-offcanvas-color)
}
#oMenuMobile .nav-link {
color:var(--tw-offcanvas-color)
}
#oMenuMobile .nav-link.active, #oMenuMobile .nav-link:hover {
color:var(--tw-offcanvas-active-color)
}
/* Retire la bordure et le « outline » autour du bouton Bootstrap */
.navbar-toggler {
border: 0 !important;
}
.navbar-toggler:focus,
.navbar-toggler:active,
.navbar-toggler-icon:focus {
outline: none !important;
box-shadow: none !important;
border: 0 !important;
}
.barres {
width: 21px;
height: 2px;
background-color: var(--tw-ham-color);
display: block;transition: all 0.2s;}
.barre-millieu4 {
margin: 4px auto;
}
/* Menu ouvert */
.navbar-toggler .barre-haut {
transform: rotate(45deg);
transform-origin: 10% 10%;
}
.navbar-toggler .barre-millieu4 {
opacity: 0;
filter: alpha(opacity=0);
}
.navbar-toggler .barre-bas {
transform: rotate(-45deg);
transform-origin: 10% 90%;
}
/* Menu fermer */
.navbar-toggler.collapsed .barre-haut {
transform: rotate(0);
}
.navbar-toggler.collapsed .barre-millieu4 {
opacity: 1;filter: alpha(opacity=100);
}
.navbar-toggler.collapsed .barre-bas {
transform: rotate(0);
}
.navbar-toggler.collapsed .barres {
background-color: var(--tw-ham-active-color);
}
<!-- exemple sombre -->
<body data-bs-theme="dark">
<!-- exemple clair -->
<body data-bs-theme="light">
<nav class="navbar bg-body">
<div class="container px-0">
<a class="navbar-brand" href="#">Trucsweb.com</a>
<button id="oBtnMenu" class="navbar-toggler collapsed" style="z-index: 1046!important;" type="button" title="Menu" data-bs-toggle="offcanvas"
data-bs-target="#oMenuMobile" aria-controls="oMenuMobile" aria-expanded="true" aria-label="Navigation">
<span class="barres barre-haut"></span>
<span class="barres barre-millieu4"></span>
<span class="barres barre-bas"></span>
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="oMenuMobile" aria-labelledby="oMenuMobileLabel">
<div class="offcanvas-header my-5">
<!-- button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Fermer"></button -->
</div>
<div class="offcanvas-body">
Test
</div>
</div>
</div>
</nav>
Noter le z-index pour positionner le bouton au dessus de l’offcanvas qui est par défaut à z-index: 1045
.
<script>
// Bouton hamburger
const oBoutonMenu = document.getElementById('oBtnMenu');
// Offcanvas
const oCanvasMenu = document.getElementById('oMenuMobile');
// Détecte le début de la fermeture de l'offcanvas
oCanvasMenu.addEventListener('hide.bs.offcanvas', event => {
// Ajoute la classe collapsed
oBoutonMenu.className = 'navbar-toggler collapsed';
})
// Détecte le début de l'ouverture de l'offcanvas
oCanvasMenu.addEventListener('show.bs.offcanvas', event => {
// Retire la classe collapsed
oBoutonMenu.className = 'navbar-toggler';
})
</script>
Résultat : Exemple du menu « offcanvas » avec bouton « Hamburger » animé
Conclusion
Pour aller plus loin, vous trouverez sur la toile un tas de scripts plus ou moins pratiques, avec parfois de superbes animations ! À vous de trouver la vôtre. Bonne 26e année de Trucsweb à toutes et à tous.
Références
- CSS Transitions - W3C
- Transforms CSS 3D - W3C
- Exemples de transformation - W3C
- Navbar - Bootstrap v5.3.0
- Offcanvas - Bootstrap v5.3.0
- Color modes - Bootstrap v5.3.0
La couleur de fond jaune tourne au rouge graduellement en 12 secondes, c’est long... Mais l’effet n’est pas réussi surtout parce que la couleur blanche change instantanément. Et vis versa!
Pour synchroniser la couleur blanche avec les 22 secondes, ajouter simplement la valeur
color
dans la transition :