Icon Morph
Le bouton menu à trois barres qui devient une croix au clic : les barres du haut et du bas glissent au centre et pivotent à ±45°, celle du milieu s'efface, le tout en 0,4 s avec un rebond et un passage du violet au rose. Un vrai bouton, utilisable au clavier, qui dit s'il est ouvert ou fermé ; croix posée sans mouvement si l'utilisateur réduit les animations.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Liquid comprend 31 effets, dont 6 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Le bouton .icon-morph est un vrai <button type="button"> de 50 × 50 px (fond violet à 15 %, bordure de 2 px, coins de 12 px) qui contient trois <span> vides : les barres, 26 × 3 px, posées en position: absolute à 15, 23 et 31 px du haut. Quand le script ajoute la classe .active, la première et la troisième barre rejoignent le centre (top: 23px) en tournant de 45° et de −45°, et passent de #a855f7 à #ec4899 ; celle du milieu s'efface (opacity: 0 et scaleX(0)). Un second clic retire la classe et refait les trois barres.
Tout passe par une seule transition : transition: .4s cubic-bezier(.68, -.55, .27, 1.55) sur les barres. Les deux valeurs hors de 0-1 dans la courbe font reculer légèrement les barres au départ puis dépasser leur position d'arrivée avant de s'y poser : c'est ce rebond qui donne l'impression d'une icône élastique plutôt que d'un simple fondu. Le script, une dizaine de lignes, parcourt tous les .fx-0402-root .icon-morph de la page, bascule .active au clic et tient aria-expanded à jour ; l'effet peut donc être collé plusieurs fois.
Pourquoi un <button> plutôt qu'un bloc cliquable : il reçoit le focus avec Tab, s'active avec Entrée et Espace sans une ligne de code, et les lecteurs d'écran l'annoncent comme bouton. Son nom reste « Menu » (aria-label) : c'est aria-expanded qui dit « réduit » ou « développé ». Changer aussi le libellé en « Fermer » ferait annoncer deux fois l'état. Le bouton ne fait qu'indiquer l'état : c'est à votre page d'ouvrir le panneau, en écoutant le clic ou en lisant aria-expanded, comme le font les trois exemples.
Accessibilité
- Clavier : mesuré dans Chromium 151 et Firefox 153, Tab atteint le bouton, Entrée comme Espace l'ouvrent puis le referment ; l'anneau de focus rose (
:focus-visible, 2 px, décalé de 3 px) ne s'affiche qu'au clavier. Dans Safari, Tab saute les boutons tant que l'option « Appuyer sur Tab pour sélectionner chaque élément » n'est pas cochée (Option+Tab les atteint) : c'est le réglage du navigateur, pas l'effet. - Lecteurs d'écran : le bouton est annoncé « Menu, bouton, réduit » puis « développé ». Reliez-le à votre panneau avec
aria-controls="id-du-panneau", et donnez au panneau un vrai contenu de liste ou de navigation. - Mouvement réduit : sous
prefers-reduced-motion: reduce, les barres n'ont plus de transition de position ni de rotation, seulement la couleur et l'opacité en 0,3 s. Mesuré dans les trois moteurs : la croix est en place dès la première image, plus aucune image ne change après 300 ms. - Cible : 50 × 50 px, au-dessus des 44 px conseillés pour un doigt. Ne descendez pas sous cette taille sur mobile.
Compatibilité navigateur
CSS (transitions de top, transform, opacity) + 0,5 Ko de JavaScript, aucune dépendance. Mesuré image par image dans Chromium 151, Firefox 153 et WebKit 26 : même trajet des barres, même rebond, même arrêt sous mouvement réduit. :focus-visible existe depuis Chrome 86, Firefox 85 et Safari 15.4 ; avant, le navigateur affiche son contour de focus habituel.
Sans JavaScript, le bouton reste à trois barres et ne change pas d'état : prévoyez que votre menu soit accessible autrement (lien vers une page de navigation, par exemple). Un navigateur sans transitions CSS passe directement des barres à la croix.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :
<div class="fx-0402-root">
<div class="icon-morph-container">
<button type="button" class="icon-morph" aria-expanded="false" aria-label="Menu">
<span></span><span></span><span></span>
</button>
<span class="icon-morph-label">…</span>
</div>
</div>
Paiement unique, sans abonnement — le code est à toi pour toujours
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Couleurs (CSS — background de .icon-morph span et des règles .active) |
barres #a855f7, croix #ec4899 |
Mettez la couleur de votre barre de navigation sur les barres et une couleur d'alerte douce sur la croix. Gardez un contraste d'au moins 3:1 avec le fond du bouton. |
Durée et rebond (CSS — transition: .4s cubic-bezier(.68, -.55, .27, 1.55)) |
0,4 s, recul puis dépassement | .3s ease donne une croix sans rebond, plus sobre ; au-delà de 0,6 s, le bouton paraît lent à répondre. |
Taille (CSS — width / height du bouton, top des barres) |
bouton 50 px, barres de 26 × 3 px à 15 / 23 / 31 px | Pour un bouton de 40 px : barres de 22 px à 11 / 18 / 25 px, et top: 18px dans les deux règles .active. Les écarts entre barres doivent rester égaux pour que la croix se croise au centre. |
Nom accessible (HTML — aria-label) |
« Menu » | Nommez ce que le bouton ouvre : « Calques », « Chapitres », « Filtres ». Ajoutez aria-controls avec l'id de votre panneau. |
Barre du milieu (CSS — .active span:nth-child(2)) |
opacity: 0 et scaleX(0) |
transform: translateX(-20px) à la place de scaleX(0) la fait sortir par la gauche au lieu de se rétracter au centre. |
FAQ
aria-expanded : btn.addEventListener('click', function () { panneau.hidden = btn.getAttribute('aria-expanded') !== 'true'; });. Placez ce code après le script de l'effet, qui met aria-expanded à jour en premier. Pensez aussi à refermer le menu avec Échap et à rendre le focus au bouton.aria-expanded porte déjà l'état : un lecteur d'écran dit « Menu, bouton, développé ». Changer aussi le nom en « Fermer le menu » ferait répéter l'information, et certains lecteurs n'annoncent pas un changement de nom sur un élément déjà sélectionné. Un nom fixe et un état qui change, c'est le modèle conseillé pour un bouton qui ouvre et ferme.top recalcule la mise en page à chaque image, là où transform ne fait que déplacer un calque déjà dessiné. Ici, cela concerne trois barres de 26 × 3 px dans un bouton de 50 px, pendant 0,4 s : le coût est négligeable, même sur un téléphone d'entrée de gamme. Si vous animez des dizaines de boutons à la fois, remplacez les top des règles .active par un translateY(8px) et translateY(-8px) placé avant la rotation.