Accueil

Créer un menu hamburger en HTML, JS et CSS

Tutoriel Web

Posté par Véronique le 25 March 2020

Voici comment créer un menu hamburger avec une structure HTML simple, un peu de JavaScript, et quand même pas mal de CSS ! Vous trouverez le code complet à la fin de l'article.


1. Le HTML

Nous allons commencer par définir la structure de notre menu en HTML. Les 3 éléments principaux étant :

  • le menu classique, celui qui sera affiché sur les écrans larges
  • l'icone hamburger
  • le menu responsive
<div id="root">
    <div id="topnav" class="topnav">
        <a id="home_link" class="topnav_link" href="/">HOME</a>

        <!-- Classic Menu -->
        <nav role="navigation" id="topnav_menu">
            ...
        </nav>

        <a id="topnav_hamburger_icon" href="javascript:void(0);" onclick="showResponsiveMenu()">
            <!-- Some spans to act as a hamburger -->
            <span></span>
            <span></span>
            <span></span>
        </a>

        <!-- Responsive Menu -->
        <nav role="navigation" id="topnav_responsive_menu">
            ...
        </nav>
    </div>
</div>

Nous préférons définir 2 éléments <nav> car cela permet de ne pas avoir exactement les mêmes éléments dans le menu classique et le menu responsive. Nous avons également ajouté un lien "HOME" qui sera présent autant en mode responsive qu'en mode classique.

2. Le JavaScript

Notre hamburger fait appel à une fonction JavaScript showResponsiveMenu(). C'est ici que nous ajoutons/retirons les classes ou propriétés CSS qui nous permette d'afficher/masquer le menu responsive.

function showResponsiveMenu() {
    var menu = document.getElementById("topnav_responsive_menu");
    var icon = document.getElementById("topnav_hamburger_icon");
    var root = document.getElementById("root");
    if (menu.className === "") {
        menu.className = "open";
        icon.className = "open";
        root.style.overflowY = "hidden";
    } else {
        menu.className = "";                    
        icon.className = "";
        root.style.overflowY = "";
    }
}

Nous modifions la propriété root.style.overflowY afin de bloquer le scrolling vertical lorsque le menu est affiché.

3. Le CSS

Pour la partie CSS, nous allons commencer par gérer le positionnement et l'affichage des éléments, selon que la largueur de l'écran fasse plus ou moins de 768px.

/* hide responsive menu */
#topnav_hamburger_icon,
#topnav_responsive_menu {
    display: none;
}

@media only screen and (max-width: 768px) {
    /* hide classic menu */
    #topnav_menu {
        display: none;
    }

    /* position home link at left and hamburger will be positionned at right */
    .topnav {
        width           : 100%;
        display         : flex;
        align-items     : center;
    }

    #home_link {
        flex-grow: 1;
    }

    /* position responsive menu at the right of the screen */
    #topnav_responsive_menu ul {
        display       : flex;
        flex-direction: column;

        position: absolute;
        margin  : 0;
        right   : 0;
        top     : 0;

        min-width: 50vw;
        height   : 100vh;
    }
}

Nous modifions la propriété display afin d'afficher/masquer les différents éléments. En mettant cette propriété à flex pour notre <div> principal, et en ajoutant la propriété flex-grow: 1 à notre lien "HOME", nous indiquons que ce lien doit prendre tout l'espace disponible, ce qui amènera notre icone hamburger à se coller tout à droite de l'écran.

Voici maintenant comme définir l'apparition du menu.

@media only screen and (max-width: 768px) {
    /* disable horizontal scrolling  */
    #root {
        position: relative;
        overflow-x: hidden;
    }

    /* position responsive menu at the right of the screen */
    #topnav_responsive_menu {
        display : block;
        position: absolute;
        right   : 0;
        top     : 0;
        margin  : 0;
        width   : 100vw;
        height  : 100vh;

        z-index: 99;

        transform-origin: 0% 0%;
        transform       : translate(200%, 0);

        transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0);
    }

    /* and let's slide it in from the right */
    #topnav_responsive_menu.open {
        transform: none;
        position : fixed;
    }
}

Ici, nous cachons, dans un premier temps, le menu responsive à droite de l'écran, à l'aide de la propriété transform : translate(200%, 0);. Cela implique l'apparition de la barre de défilement verticale. Nous ajoutons donc 2 propriétés à notre <div id="root"> pour la désactiver.

En enlevant la propriété transform, le menu va apparaitre depuis la droite de l'écran.

Et pour finir, voici le CSS permettant d'afficher et d'animer l'icone hamburger à partir des 3 spans. Pour cela, on utilise les propriétés suivantes :

  • transform: rotate() pour indiquer le degré de rotation a effectuer => 45° pour le 1er span et -45° pour le dernier, afin de transformer notre hamburger en X.
  • transform-origin
  • transition pour définir le temps et le style d'animation
@media only screen and (max-width: 768px) {
    /* define size and position of the hamburger link */
    #topnav_hamburger_icon {
        display    : block;
        position   : relative;
        margin     : 16px;
        width      : 33px;
        height     : 28px;
        z-index    : 100;
        user-select: none;
        cursor     : pointer;
    }

    /* define the style (size, color, position, animation, ...) of the 3 spans */
    #topnav_hamburger_icon span {
        display      : block;
        position     : absolute;
        height       : 4px;
        width        : 100%;
        margin-bottom: 5px;
        background   : #ededed;
        border-radius: 3px;
        z-index      : 100;
        opacity      : 1;
        left         : 0;

        transform : rotate(0deg);
        transition: .25s ease-in-out;
    }

    /* set the 3 spans position to look like a hamburger */
    #topnav_hamburger_icon span:nth-child(1) {
        top             : 0px;
        transform-origin: left top;
    }
    #topnav_hamburger_icon span:nth-child(2) {
        top             : 12px;
        transform-origin: left center;
    }
    #topnav_hamburger_icon span:nth-child(3) {
        top             : 24px;
        transform-origin: left bottom;
    }

    /* the first span rotates 45° \ */
    #topnav_hamburger_icon.open span:nth-child(1) {
        width    : 110%;
        transform: rotate(45deg);
    }
    /* the second span disappears */
    #topnav_hamburger_icon.open span:nth-child(2) {
        width  : 0%;
        opacity: 0;
    }
    /* the last span rotates -45° / */
    #topnav_hamburger_icon.open span:nth-child(3) {
        width    : 110%;
        transform: rotate(-45deg);
    }
}

Le code complet

HTML

<div id="root">
  <div id="topnav" class="topnav">
    <a id="home_link" class="topnav_link" href="/">HOME</a>

    <!-- Classic Menu -->
    <nav role="navigation" id="topnav_menu">
      <a class="topnav_link" href="/about">ABOUT</a>
      <a class="topnav_link" href="/contact-us">CONTACT</a>
    </nav>

    <a id="topnav_hamburger_icon" href="javascript:void(0);" onclick="showResponsiveMenu()">
      <!-- Some spans to act as a hamburger -->
      <span></span>
      <span></span>
      <span></span>
    </a>

    <!-- Responsive Menu -->
    <nav role="navigation" id="topnav_responsive_menu">
      <ul>
        <li><a href="/">HOME</a></li>
        <li><a href="/about">ABOUT</a></li>
        <li><a href="/contact-us">CONTACT</a></li>
        <li><a href="/privacy-policy">PRIVACY POLICY</a></li>
        <li><a href="/terms-and-conditions">TERMS AND CONDITIONS</a></li>
      </ul>
    </nav>
  </div>
</div>

JS

function showResponsiveMenu() {
  var menu = document.getElementById("topnav_responsive_menu");
  var icon = document.getElementById("topnav_hamburger_icon");
  var root = document.getElementById("root");
  if (menu.className === "") {
    menu.className = "open";
    icon.className = "open";
    root.style.overflowY = "hidden";
  } else {
    menu.className = "";                    
    icon.className = "";
    root.style.overflowY = "";
  }
}

CSS

/* ******************** NAV BAR ******************** */
.topnav {
  background-color: #333;
  display: flex;
  align-items: center;
  width: 100%;
}
.topnav_link {
  color: white;
  padding: 12px;
  text-decoration: none;
}
.topnav_link:hover {
  color: #0078b4;
}

/* hide responsive menu */
#topnav_hamburger_icon,
#topnav_responsive_menu {
  display: none;
}

@media only screen and (max-width: 768px) {
  /* hide classic menu */
  #topnav_menu {
    display: none;
  }

  /* position home link at left and hamburger at right */
  #home_link {
    flex-grow: 1;
  }

  /* disable horizontal scrolling  */
  #root {
    position: relative;
    overflow-x: hidden;
  }

  /* show responsive menu and position at the right of the screen */
  #topnav_responsive_menu {
    display: block;
    position: absolute;
    margin: 0;
    right: 0;
    top: 0;
    width: 100vw;
    height: 100vh;

    z-index: 99;

    transform-origin: 0% 0%;
    transform: translate(200%, 0);

    transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1);
  }

  #topnav_responsive_menu ul {
    display: flex;
    flex-direction: column;

    position: absolute;
    margin: 0;
    right: 0;
    top: 0;

    min-width: 50vw;
    height: 100vh;
    padding: 56px 0 0;

    text-align: center;

    background: #ededed;
    list-style-type: none;
    -webkit-font-smoothing: antialiased;
  }

  #topnav_responsive_menu li {
    padding: 12px 24px;
  }

  #topnav_responsive_menu a {
    white-space: nowrap;
    color: #333;
    text-decoration: none;
  }

  /* And let's slide it in from the right */
  #topnav_responsive_menu.open {
    transform: none;
    position: fixed;
  }

  /* ******************** HAMBURGER ICON ******************** */
  /* define size and position of the hamburger link */
  #topnav_hamburger_icon {
    display: block;
    position: relative;
    margin: 16px;
    width: 33px;
    height: 28px;

    z-index: 100;

    -webkit-user-select: none;
    user-select: none;
    cursor: pointer;
  }

  /* define the style (size, color, position, animation, ...) of the 3 spans */
  #topnav_hamburger_icon span {
    display: block;
    position: absolute;
    height: 4px;
    width: 100%;
    margin-bottom: 5px;

    background: #ededed;
    border-radius: 3px;

    z-index: 100;

    opacity: 1;
    left: 0;

    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
    -webkit-transition: 0.25s ease-in-out;
    -moz-transition: 0.25s ease-in-out;
    -o-transition: 0.25s ease-in-out;
    transition: 0.25s ease-in-out;
  }

  /* set the 3 spans position to look like a hamburger */
  #topnav_hamburger_icon span:nth-child(1) {
    top: 0px;
    -webkit-transform-origin: left top;
    -moz-transform-origin: left top;
    -o-transform-origin: left top;
    transform-origin: left top;
  }
  #topnav_hamburger_icon span:nth-child(2) {
    top: 12px;
    -webkit-transform-origin: left center;
    -moz-transform-origin: left center;
    -o-transform-origin: left center;
    transform-origin: left center;
  }
  #topnav_hamburger_icon span:nth-child(3) {
    top: 24px;
    -webkit-transform-origin: left bottom;
    -moz-transform-origin: left bottom;
    -o-transform-origin: left bottom;
    transform-origin: left bottom;
  }

  /* change color when opening the menu */
  #topnav_hamburger_icon.open span {
    background: #333;
  }

  /* the first span rotates 45° \ */
  #topnav_hamburger_icon.open span:nth-child(1) {
    width: 110%;
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
    -o-transform: rotate(45deg);
    transform: rotate(45deg);
  }

  /* the second span disappears */
  #topnav_hamburger_icon.open span:nth-child(2) {
    width: 0%;
    opacity: 0;
  }

  /* the last span rotates -45° / */
  #topnav_hamburger_icon.open span:nth-child(3) {
    width: 110%;
    -webkit-transform: rotate(-45deg);
    -moz-transform: rotate(-45deg);
    -o-transform: rotate(-45deg);
    transform: rotate(-45deg);
  }
}

sources :