Aujourd'hui nous allons apprendre à animer l'icône hamburger, cette fameuse icône composée de 3 traits horizontaux qui est de plus en plus incontournable.

HTML

Au niveau du code HTML on va essayer de rester le plus simple possible en évitant au maximum les éléments inutiles

    <div class="menu-icon">
      <span></span>
    </div>

Malheureusement, on sera tout de même obligé de rajouter un élément vide à l'intérieur de notre élément pour créer les 3 petits traits. L'élément .menu-icon permettra de définir la zone cliquable mais aussi de mettre un fond si besoin.

L'icône en CSS

Notre but est donc de transformer cette <span> en 3 petit traits. On va commencer par transformer notre span en un trait vertical centré.

.menu-icon{
    position: relative; 
    width: 54px;
    height: 54px; 

    transition: transform 0.5s;
}
.menu-icon span {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translateX(-50%) translateY(-50%); 

    display: block;
    width: 22px;
    height: 2px;

    background-color: #FFF;

    transition: background 0.5s;
}

Ensuite on va utiliser les pseudos éléments ::before et ::after afin de créer la barre au dessus et en dessous.

.menu-icon span::before, .menu-icon span::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    transform: translateY(-6px);

    display: block;
    width: 22px;
    height: 2px;

    background-color: #FFF;

    transition: transform 0.5s;
}
.menu-icon span::after {
    transform: translateY(6px); 
}

Et hop le tour est joué il nous reste plus qu'à animer

De l'icône vers la croix

On veut maintenant transformer notre icône en croix lorsque la classe de notre élément devient .is-opened. Pour cela, on va faire tourner nos 2 traits horizontaux de 45 degrés tout en faisant disparaitre le trait central en changeant son background-color. On ne peut pas jouer ici sur l'opacité car cela affecterait aussi les pseudo éléments

.menu-icon.is-opened span { background: transparent; }
.menu-icon.is-opened span::before { transform: translateY(0) rotate(45deg); }
.menu-icon.is-opened span::after { transform: translateY(0) rotate(-45deg); }

Pour rendre l'effet encore plus sympa nous allons effectuer une rotation sur le parent de 180 degrés pour accentuer la transition.

.menu-icon.is-opened { transform: rotate(180deg); }

Bordures animées

Nous avons le squelette de notre animation, mais on souhaite ajouter autour de notre élément une bordure qui évolue en cercle. Malheureusement, on ne peut pas faire ça simplement et on va devoir faire appel à nos amis les SVG.

On va commencer par créer un cercle que l'on place dans notre élément .menu-icon

<div class="menu-icon">
  <span></span>
  <svg x="0" y="0" width="54px" height="54px" viewBox="0 0 54 54">
    <circle cx="27" cy="27" r="26"></circle>
  </svg>
</div>

On stylise ensuite le SVG en CSS pour faire apparaitre la bordure.

  .menu-icon svg {
    position: relative;
    z-index: 1;
    fill: #052b23;
    stroke-width: 1px;
    stroke: #FFF;
}

On a maintenant notre bordure blanche mais comment l'animer ? On peut jouer sur 2 propriétés intéréssantes des SVG

  • stroke-dasharray, permet de transformer notre bordure en pointillés. On pourra alors indiquer la taille des pointillés et des espaces blancs.
  • stroke-dashoffset, permet de décaler le démarrage des tirets

Gràce au pouvoir des mathématiques, on va pouvoir utiliser ces 2 propriétés à notre avantage.
Notre cercle a un diamètre de 54px donc la circonférence du cercle fait 169.56px. On va utiliser cette valeur pour le stroke-dasharray pour avoir un tiret qui fait la taille du cercle (on arrondira à 170px) puis il nous suffira d'animer le stroke-dashoffset pour obtenir une animation de "remplissage" de la bordure.

 .menu-icon svg { 
    stroke-dashoffset: 170;
    stroke-dasharray: 170;
    transition: stroke-dashoffset 0.5s; 
 }
 .menu-icon.is-opened{
    stroke-dashoffset: 0; 
 }

Et voila ! C'est une astuce toute bête, mais qu'il est important de bien comprendre pour être à l'aise avec le principe et pour pouvoir l'utiliser dans d'autres cas.