Accessible Expanding Navigation With JavaScript And CSS3

Category: Javascript , Menu & Navigation | October 4, 2017
Authormxbck
Last UpdateOctober 4, 2017
LicenseMIT
Tags
Views393 views
Accessible Expanding Navigation With JavaScript And CSS3

An animated accessible navigation that expands the hamburger menu toggle button into a fullscreen navigation menu when toggled.

How to use it:

Insert the navigation menu, menu toggle button, and background element to the web page.

<header class="header" role="banner">
  
  <nav id="nav" class="nav" role="navigation">
    
    <!-- ACTUAL NAVIGATION MENU -->
    <ul class="nav__menu" id="menu" tabindex="-1" aria-label="main navigation" hidden>
      <li class="nav__item"><a href="#" class="nav__link">Home</a></li>
      <li class="nav__item"><a href="#" class="nav__link">Shop</a></li>
      <li class="nav__item"><a href="#" class="nav__link">Blog</a></li>
      <li class="nav__item"><a href="#" class="nav__link">About</a></li>
      <li class="nav__item"><a href="#" class="nav__link">Contact</a></li>
    </ul>
    
    <!-- MENU TOGGLE BUTTON -->
    <a href="#nav" class="nav__toggle" role="button" aria-expanded="false" aria-controls="menu">
      <svg class="menuicon" xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 50 50">
        <title>Toggle Menu</title>
        <g>
          <line class="menuicon__bar" x1="13" y1="16.5" x2="37" y2="16.5"/>
          <line class="menuicon__bar" x1="13" y1="24.5" x2="37" y2="24.5"/>
          <line class="menuicon__bar" x1="13" y1="24.5" x2="37" y2="24.5"/>
          <line class="menuicon__bar" x1="13" y1="32.5" x2="37" y2="32.5"/>
          <circle class="menuicon__circle" r="23" cx="25" cy="25" />
        </g>
      </svg>
    </a>
    
    <!-- ANIMATED BACKGROUND ELEMENT -->
    <div class="splash"></div>
    
  </nav>
  
</header>

The primary CSS/CSS3 rules for the navigation.

.nav__toggle {
  display: inline-block;
  position: absolute;
  z-index: 10;
  padding: 0;
  border: 0;
  background: transparent;
  outline: 0;
  right: 15px;
  top: 15px;
  cursor: pointer;
  border-radius: 50%;
  -webkit-transition: background-color .15s linear;
  transition: background-color .15s linear;
}
.nav__toggle:hover, .nav__toggle:focus { background-color: rgba(0, 0, 0, 0.5); }
.nav__menu {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  height: var(--screen-height);
  position: relative;
  z-index: 5;
  visibility: hidden;
}
.nav__item {
  opacity: 0;
  -webkit-transition: all 0.3s cubic-bezier(0, 0.995, 0.99, 1) 0.3s;
  transition: all 0.3s cubic-bezier(0, 0.995, 0.99, 1) 0.3s;
}
.nav__item:nth-child(1) {
  -webkit-transform: translateY(-40px);
  transform: translateY(-40px);
}
.nav__item:nth-child(2) {
  -webkit-transform: translateY(-80px);
  transform: translateY(-80px);
}
.nav__item:nth-child(3) {
  -webkit-transform: translateY(-120px);
  transform: translateY(-120px);
}
.nav__item:nth-child(4) {
  -webkit-transform: translateY(-160px);
  transform: translateY(-160px);
}
.nav__item:nth-child(5) {
  -webkit-transform: translateY(-200px);
  transform: translateY(-200px);
}
.nav__link {
  color: white;
  display: block;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 5px;
  font-size: 1.25rem;
  text-decoration: none;
  padding: 1rem;
}
.nav__link:hover, .nav__link:focus {
  outline: 0;
  background-color: rgba(0, 0, 0, 0.2);
}
.menuicon {
  display: block;
  cursor: pointer;
  color: white;
  -webkit-transform: rotate(0deg);
  transform: rotate(0deg);
  -webkit-transition: 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
  transition: 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.menuicon__bar, .menuicon__circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
}
.menuicon__bar {
  -webkit-transform: rotate(0deg);
  transform: rotate(0deg);
  -webkit-transform-origin: 50% 50%;
  transform-origin: 50% 50%;
  -webkit-transition: -webkit-transform .25s ease-in-out;
  transition: -webkit-transform .25s ease-in-out;
  transition: transform .25s ease-in-out;
  transition: transform .25s ease-in-out, -webkit-transform .25s ease-in-out;
}
.menuicon__circle {
  -webkit-transition: stroke-dashoffset .3s linear .1s;
  transition: stroke-dashoffset .3s linear .1s;
  stroke-dashoffset: 144.51326;
  stroke-dasharray: 144.51326;
}
.splash {
  position: absolute;
  top: 40px;
  right: 40px;
  width: 1px;
  height: 1px;
}
.splash::after {
  content: "";
  display: block;
  position: absolute;
  border-radius: 50%;
  background-color: var(--splash-bg-color);
  width: 284vmax;
  height: 284vmax;
  top: -142vmax;
  left: -142vmax;
  -webkit-transform: scale(0);
  transform: scale(0);
  -webkit-transform-origin: 50% 50%;
  transform-origin: 50% 50%;
  -webkit-transition: -webkit-transform 0.5s cubic-bezier(0.755, 0.05, 0.855, 0.06);
  transition: -webkit-transform 0.5s cubic-bezier(0.755, 0.05, 0.855, 0.06);
  transition: transform 0.5s cubic-bezier(0.755, 0.05, 0.855, 0.06);
  transition: transform 0.5s cubic-bezier(0.755, 0.05, 0.855, 0.06), -webkit-transform 0.5s cubic-bezier(0.755, 0.05, 0.855, 0.06);
  will-change: transform;
}
.nav:target > .splash::after, .nav--open > .splash::after {
  -webkit-transform: scale(1);
  transform: scale(1);
}
.nav:target .menuicon, .nav--open .menuicon {
  color: white;
  -webkit-transform: rotate(180deg);
  transform: rotate(180deg);
}
.nav:target .menuicon__circle, .nav--open .menuicon__circle { stroke-dashoffset: 0; }
.nav:target .menuicon__bar:nth-child(1), .nav:target .menuicon__bar:nth-child(4), .nav--open .menuicon__bar:nth-child(1), .nav--open .menuicon__bar:nth-child(4) { opacity: 0; }
.nav:target .menuicon__bar:nth-child(2), .nav--open .menuicon__bar:nth-child(2) {
  -webkit-transform: rotate(45deg);
  transform: rotate(45deg);
}
.nav:target .menuicon__bar:nth-child(3), .nav--open .menuicon__bar:nth-child(3) {
  -webkit-transform: rotate(-45deg);
  transform: rotate(-45deg);
}
.nav:target .nav__menu, .nav--open .nav__menu { visibility: visible; }
.nav:target .nav__item, .nav--open .nav__item {
  opacity: 1;
  -webkit-transform: translateY(0);
  transform: translateY(0);
}

The JavaScript to activate the navigation.

'use strict';
var nav = document.querySelector('#nav');
var menu = document.querySelector('#menu');
var menuToggle = document.querySelector('.nav__toggle');
var isMenuOpen = false;
// TOGGLE MENU ACTIVE STATE
menuToggle.addEventListener('click', function (e) {
  e.preventDefault();
  isMenuOpen = !isMenuOpen;
  // toggle a11y attributes and active class
  menuToggle.setAttribute('aria-expanded', String(isMenuOpen));
  menu.hidden = !isMenuOpen;
  nav.classList.toggle('nav--open');
});
// TRAP TAB INSIDE NAV WHEN OPEN
nav.addEventListener('keydown', function (e) {
  // abort if menu isn't open or modifier keys are pressed
  if (!isMenuOpen || e.ctrlKey || e.metaKey || e.altKey) {
    return;
  }
  // listen for tab press and move focus
  // if we're on either end of the navigation
  var menuLinks = menu.querySelectorAll('.nav__link');
  if (e.keyCode === 9) {
    if (e.shiftKey) {
      if (document.activeElement === menuLinks[0]) {
        menuToggle.focus();
        e.preventDefault();
      }
    } else if (document.activeElement === menuToggle) {
      menuLinks[0].focus();
      e.preventDefault();
    }
  }
});

You Might Be Interested In:


Leave a Reply