Feature-rich Off Canvas Menu using JavaScript

Feature-rich Off Canvas Menu using JavaScript
Project: Off-canvas Navigation Variants (Sidebar)
Author: foxeisen
Edit Online: View on CodePen
License: MIT

An off-canvas menu is a navigation menu that is hidden by default and slides into view when triggered, creating a smooth and interactive user experience. This code provides a feature-rich off-canvas menu implemented using JavaScript.

The JavaScript code handles the opening and closing of the off-canvas menu. When the user clicks on the hamburger button, the menu slides into view, and the button is hidden. Similarly, when the user clicks on the navigation close button or anywhere outside the menu, the menu closes and the open button reappears. This code ensures a smooth and intuitive user experience.

How to Create Off Canvas Menu Using JavaScript

1. First of all, load the Google Fonts and Material Design Icons by adding the following CDN links to the head tag of your web/app project.

<link href="https://fonts.googleapis.com/css?family=Overpass:400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=The+Girl+Next+Door" rel="stylesheet">
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/material-design-icons/3.0.1/iconfont/material-icons.min.css'>

2. Create the HTML structure for the off-canvas menu as follows:

<!--page block includes a navigation and a content block -->
<div class="page">
  <!--navigation-->
  <nav class="nav">
    <!--close button-->
    <div class="nav__close"></div>
    <!--navigation list-->
    <ul class="nav__list">
      <!--navigation item-->
      <li class="nav__item">
        <!--navigation link--><a class="nav__link" href="#" title="Home"><i class="nav__link-icon material-icons">home</i>Home</a>
      </li>
      <!--navigation item-->
      <li class="nav__item">
        <!--navigation link--><a class="nav__link" href="#" title="About"><i class="nav__link-icon material-icons">equalizer</i>About</a>
      </li>
      <!--navigation item-->
      <li class="nav__item">
        <!--navigation link--><a class="nav__link" href="#" title="Tour"><i class="nav__link-icon material-icons">business_center</i>Tour</a>
      </li>
      <!--navigation item-->
      <li class="nav__item">
        <!--navigation link--><a class="nav__link" href="#" title="Settings"><i class="nav__link-icon material-icons">settings</i>Settings</a>
      </li>
      <!--navigation item-->
      <li class="nav__item">
        <!--navigation link--><a class="nav__link" href="#" title="Plans"><i class="nav__link-icon material-icons">grade</i>Plans</a>
      </li>
      <!--navigation item-->
      <li class="nav__item">
        <!--navigation link--><a class="nav__link" href="#" title="Log In"><i class="nav__link-icon material-icons">perm_identity</i>Log In</a>
      </li>
    </ul>
  </nav>
  <!--content part-->
  <div class="page__content">
    <!--open navigation button-->
    <div class="nav-open-btn">
      <div class="nav-open-btn__bar"></div>
      <div class="nav-open-btn__bar"></div>
      <div class="nav-open-btn__bar"></div>
    </div>
    <!--content block-->
    <div class="content">
     
      <!--Your Content Goes Here -->
      
    </div>
  </div>
</div>

3. Use the following CSS code to style the off-canvas menu.

/* navigation styles */
.nav {
  position: fixed;
  top: 0;
  bottom: 0;
  width: 300px;
  padding: 30px;
  box-sizing: border-box;
  background-color: #1c1c1c;
  box-shadow: 4px 0 5px 0 rgba(0, 0, 0, 0.14), 1px 0 10px 0 rgba(0, 0, 0, 0.12), 2px 0 4px -1px rgba(0, 0, 0, 0.3);
  opacity: 0;
  visibility: hidden;
  z-index: 500;
}

/* nav list styles */
.nav__list {
  position: relative;
  padding: 0;
  margin: 45px 0 0 0;
  list-style-type: none;
}

/* nav item styles */
.nav__item:not(:last-child) {
  margin-bottom: 20px;
}

/* nav link styles */
.nav__link {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  display: inline-flex;
  align-items: center;
  color: #fff;
  text-decoration: none;
}
.nav__link:hover {
  color: #4caf50;
}

/* nav link icon styles */
.nav__link-icon {
  position: relative;
  top: -3px;
  /* !!!use only with material design icons */
  margin-right: 10px;
  color: currentColor;
}

/* close icon styles */
.nav__close {
  position: absolute;
  top: 30px;
  right: 30px;
  width: 40px;
  height: 25px;
  cursor: pointer;
  /* close icon elements */
  /* hover effect */
}
.nav__close:before, .nav__close:after {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  display: block;
  width: 4px;
  height: 28px;
  border-radius: 10px;
  content: "";
  transform-origin: center center;
  background-color: #fff;
}
.nav__close:before {
  position: absolute;
  top: 0;
  left: 18px;
  transform: rotate(-45deg);
}
.nav__close:after {
  position: absolute;
  top: 0;
  right: 18px;
  transform: rotate(45deg);
}
.nav__close:hover:before, .nav__close:hover:after {
  background-color: #4caf50;
}

/* nav open btn styles */
.nav-open-btn {
  position: absolute;
  top: 30px;
  left: 30px;
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  width: 35px;
  height: 25px;
  overflow: hidden;
  cursor: pointer;
}
.nav-open-btn.js-hidden {
  transition-property: all;
  transition-duration: 0s;
  transition-timing-function: linear;
  transition-delay: 0s;
  opacity: 0;
  visibility: hidden;
}

.nav-open-btn__bar {
  width: 100%;
  height: 5px;
  background-color: #1c1c1c;
  border-radius: 20px;
}
.nav-open-btn__bar:nth-child(1) {
  position: absolute;
  top: 0;
  left: 0;
}
.nav-open-btn__bar:nth-child(2) {
  position: absolute;
  top: 10px;
  left: 0;
}
.nav-open-btn__bar:nth-child(3) {
  position: absolute;
  top: 20px;
  left: 0;
}

/* Demo #1: styles */
.nav--offcanvas-1 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: -300px;
  /* opened styles */
}
.nav--offcanvas-1.js-opened {
  transition-property: left;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 0;
  opacity: 1;
  visibility: visible;
}

.page__content--offcanvas-1 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 0;
  /* opened styles */
}
.page__content--offcanvas-1.js-opened {
  transition-property: all;
  transition-duration: 0.3s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 300px;
}

/* Demo #2: styles */
.nav--offcanvas-2 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: -300px;
  /* opened styles */
}
.nav--offcanvas-2.js-opened {
  transition-property: left;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 0;
  opacity: 1;
  visibility: visible;
}

.page__content--offcanvas-2 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  transform: scale(1) translateX(0);
}
.page__content--offcanvas-2.js-opened {
  transform: scale(0.8) translateX(150px);
}

/* Demo #3: styles */
.nav--offcanvas-3 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: -300px;
  /* opened styles */
}
.nav--offcanvas-3.js-opened {
  transition-property: left;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 0;
  opacity: 1;
  visibility: visible;
}

.page__content--offcanvas-3 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  transform: rotateY(0deg) translateX(0);
}
.page__content--offcanvas-3.js-opened {
  transform: translate3d(100px, 0, -600px) rotateY(-20deg);
}

/* Demo #4: styles */
.nav--offcanvas-4 {
  transition-property: all;
  transition-duration: 0s;
  transition-timing-function: linear;
  transition-delay: 0s;
  max-height: 80%;
  transform: rotateY(-75deg) translateX(-50px);
  transform-origin: left center;
  /* opened styles */
}
.nav--offcanvas-4.js-opened {
  max-height: 100%;
  transition: transform 0.22s linear 0s, opacity 0.22s linear 0s, visibility 0.22s linear 0s;
  transform: rotateY(0) translateX(0);
  transform-origin: left center;
  opacity: 1;
  visibility: visible;
}

.page__content--offcanvas-4 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 0;
  /* opened styles */
}
.page__content--offcanvas-4.js-opened {
  left: 300px;
}

/* Demo #5: styles */
.nav--offcanvas-5 {
  width: 50%;
}
.nav--offcanvas-5.js-opened {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  width: 300px;
  opacity: 1;
  visibility: visible;
}

.page__content--offcanvas-5 {
  transition-property: all;
  transition-duration: 0.2s;
  transition-timing-function: linear;
  transition-delay: 0s;
  left: 0;
  /* opened styles */
}
.page__content--offcanvas-5.js-opened {
  left: 300px;
}

4. Finally, add the following JavaScript code to your project to activate the toggle functionality of menu.

//hide nav open btn when the nav is open, adding/removing open classes to nav and content
var navOpenBtn = document.querySelector('.nav-open-btn');
var navCloseBtn = document.querySelector('.nav__close');
var nav = document.querySelector('.nav');
var pageContent = document.querySelector('.page__content');
var navList = document.querySelector('.nav__list');
var page = document.querySelector('.page');

//open nav
navOpenBtn.addEventListener('click', function() {
  navOpenBtn.classList.add('js-hidden');
  
  nav.classList.add('js-opened');
  
  pageContent.classList.add('js-opened');
});

//close nav
navCloseBtn.addEventListener('click', function() {
  navOpenBtn.classList.remove('js-hidden');
  
  nav.classList.remove('js-opened');
  
  pageContent.classList.remove('js-opened');
});

//closing navigation if click outside it
page.addEventListener('click', function(e) {
  
  var evTarget = e.target;
  
  if((evTarget !== nav) && (nav.classList.contains('js-opened')) && (evTarget !== navOpenBtn) && (evTarget.parentNode !== navOpenBtn)) {
    console.log(navOpenBtn.firstChild);
    
    navOpenBtn.classList.remove('js-hidden');
  
    nav.classList.remove('js-opened');
  
    pageContent.classList.remove('js-opened');
  }
  
});

The off canvas menu offers a range of five unique variants, each showcased on the demo page. Incorporating any of these demos into your project is a breeze; simply assign a specific class name to the `<nav>` element. The class names you can use range from `nav–offcanvas-1` to `nav–offcanvas-5`. By adding the appropriate class, you can effortlessly integrate the desired off canvas menu variant into your project.

That’s all! hopefully, you have successfully created a feature-rich off canvas menu using JavaScript. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply