Menu latéral glissant

Extrait de code pour un menu latéral qui s'ouvre et se ferme avec un focus clavier accessible.

Règles d’implémentation pour l’accessibilité

Le menu latéral de navigation suit les mêmes règles que le menu navigation déroulant.
La particularité supplémentaire de ce menu est que, à l’ouverture, le focus clavier sera positionné sur le bouton qui permet de refermer le menu.

Visuel

Voir aussi le menu latéral glissant sur CodePen.

Extraits de code

Code HTML

<aside id="mySidenav" class="close">
  <nav role="navigation">
    <button id="closenav">
      <span aria-hidden="true">&times;</span>
      <span class="sr-only">Fermer le menu de navigation</span>
    </button>
    <ul>
      <li><a href="#">À propos</a></li>
      <li><a href="#">Services</a></li>
      <li><a href="#">Clients</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>
</aside>
<main role="main" id="main">
  <button id="opennav" aria-expanded="false" aria-controls="mySidenav">
    <span aria-hidden="true">&#9776;</span>
    <span class="sr-only">Ouvrir le menu de navigation</span>
  </button>

  <p>Cliquez sur l'icône hamburger pour ouvrir le menu de navigation latéral et poussez ce contenu vers la droite.</p>

</main>

Code CSS

Pour adapter la couleur de la barre de navigation et des liens, modifier les codes couleurs dans la déclaration :root.

    :root {
      --MENU-BACKGROUND-color: #161616;
      --MENU-color: #FFF;
      --MENU-FOCUS-color: #FFD700;
      --FOCUS-color: #135784;

      --SIDENAV-OPEN : 250px;
      --SIDENAV-CLOSE : 0;
    }

    * {
      font-family: Arial, Helvetica, sans-serif;
    }

    *:focus {
      outline: 3px solid var(--FOCUS-color);
      outline-offset: 1px;
    }

    body.opaque {
    background-color: #00000066;
    }

    .sr-only {
      position: absolute;
      left: -10000px;
      top: auto;
      width: 1px;
      height: 1px;
      overflow: hidden;
    }

    button {
      background: none;
      border: 0;
      color: inherit;
      /* cursor: default; */
      font: inherit;
      line-height: normal;
      overflow: visible;
      padding: 0;
    }

    #mySidenav {
      height: 100%;
      position: fixed;
      z-index: 1;
      top: 0;
      left: 0;
      background-color: var(--MENU-BACKGROUND-color);
      overflow-x: hidden;
      transition: 0.5s;
      padding-top: 4em;
    }
    
    #mySidenav a,
    #mySidenav button {
      padding: .5em;
      text-decoration: none;
      font-size: 1.2em;
      color: #818181;
      display: block;
    }

    #mySidenav button {
      padding: 0 .5em;
    }

    #mySidenav a:hover,
    #mySidenav a:focus,
    #mySidenav button:hover,
    #mySidenav button:focus {
      color: var(--MENU-color);
    }

    #mySidenav button#closenav {
      position: absolute;
      top: .35em;
      right: .5em;
      font-size: 1.5em !important;
    }

    #closenav:focus,
    #closenav:hover {
      outline: 3px solid var(--MENU-FOCUS-color);
    }
    #mySidenav.close {
      width: var(--SIDENAV-CLOSE);
      visibility: hidden;
    }
    #mySidenav.close + main {
    margin-left: var(--SIDENAV-CLOSE);
    }
    #mySidenav.open {
      width: var(--SIDENAV-OPEN);
      visibility: visible;
    }
    #mySidenav.open + main {
      margin-left:var(--SIDENAV-OPEN);
    }
    #opennav {
      padding: .5em;
    }
    #opennav:focus,
    #opennav:hover {
      outline: 3px solid var(--FOCUS-color);
    }

    main {
      transition: margin-left .5s;
    }

    @media screen and (max-height: 450px) {
      #mySidenav {
        padding-top: 15px;
      }

      #mySidenav a {
        font-size: 18px;
      }
    }

    #mySidenav ul {
      margin: 2em 0 0 0;
      padding: 0;
      list-style: none;
    }

Code javascript

function openNav() {
  document.getElementById("mySidenav").classList.remove('close');
  document.getElementById("mySidenav").classList.add('open');
  document.querySelector("body").classList.add('opaque');
  document.getElementById("opennav").setAttribute('aria-expanded', 'true');
  document.getElementById("main").setAttribute('aria-hidden', 'true');
  var mainLinks = document.querySelector("main").getElementsByTagName("a");
  for (var i = 0; i < mainLinks.length; i++) {
    mainLinks[i].setAttribute('tabindex', '-1');
  }
  var mainButtons = document.querySelector("main").getElementsByTagName("button");
  for (var i = 0; i < mainButtons.length; i++) {
    mainButtons[i].setAttribute('disabled', 'true');
  }
  
  setTimeout(function () { document.getElementById("closenav").focus(); }, 500);
}

function closeNav() {
  document.getElementById("mySidenav").classList.remove('open');
  document.getElementById("mySidenav").classList.add('close');
  document.querySelector("body").removeAttribute("class");
  document.getElementById("opennav").setAttribute('aria-expanded', 'false');
  document.querySelector("main").removeAttribute('aria-hidden');
  var mainLinks = document.querySelector("main").getElementsByTagName("a");
  for (var i = 0; i < mainLinks.length; i++) {
    mainLinks[i].removeAttribute('tabindex');
  }
  var mainButtons = document.querySelector("main").getElementsByTagName("button");
  for (var i = 0; i < mainButtons.length; i++) {
    mainButtons[i].removeAttribute('disabled');
  }
  setTimeout(function () { document.getElementById("opennav").focus(); }, 500);
}


document.getElementById("opennav").addEventListener("click", openNav );
document.getElementById("closenav").addEventListener("click", closeNav );