Easy Off Canvas Menu Article

More and more the distinction between native app and web app are blurring. One of the design techniques that came into being from native apps is the off canvas menu. This technique has made its way over to web apps. But for whatever reason, it is somewhat confusing to understand to the front end developer. We are used to seeing and interacting with things that we can see on the screen at that time. In this tutorial I hope to give you a good base on how to create an off canvas menu and how to animated it using CSS and jQuery.

In order to create an off canvas menu, we have to understand how it is working beyond the viewport, or what you see in your browser window. Here is an animation on what is happening behind the scenes.

Easy Off Canvas Menu Animation

The Markup

We need to get our markup just right in order to do this correctly.

<div class="site-wrapper">
  <div class="site-canvas">
    <div class="side-nav"></div>
    <div class="page-content">
      <a href="#" class="toggle-nav"><span></span></a>
    </div>
  </div>
</div>

In this markup we have a couple of elements. The .site-wrapper contains everything and will effectually be our viewport. The .site-canvas will be the active viewport of the content, and will be animated to show the navigation. The .side-nav will of course be our menu that will be off the canvas. The .page-content will be the normal page's content. We will also have a hamburger menu to activate the menu sliding out (for the record, I hate the term hamburger menu).

The CSS

We need to prep our site to handle 100% height objects. This is simply handled by:

html, body {
  height: 100%;
}

We will also be using LESS. I have included a few LESS mixins to handle vendor prefixes. If you don't know LESS you can look at the demo's compiled CSS to see what is going on. The mixins we are using are:

// Transition Mixin
.transition (@prop: all, @time: 0.2s, @ease: linear) {
  -webkit-transition: @prop @time @ease;
          transition: @prop @time @ease;
}

// Translate
.translate(@x: 0; @y: 0) {
  -webkit-transform: translate(@x, @y);
      -ms-transform: translate(@x, @y);
          transform: translate(@x, @y);
}

// Rotate
.rotate(@degrees) {
  -webkit-transform: rotate(@degrees);
      -ms-transform: rotate(@degrees);
          transform: rotate(@degrees);
}

First we must style the .site-wrapper. We set it to position relative to prepare content's position, set the height to 100%, and set the overflow to hidden so nothing leaks.

.site-wrapper {
  position: relative;
  overflow: hidden;
  height: 100%;
}

Next we style .site-canvas. We set the width and height to 100%, set the position to relative as well, and call a transition mixin using the default mixin values.

.site-canvas {
  width: 100%;
  height: 100%;
  position: relative;
  .transition();
}

The .side-nav is set to a width of 280px and positioned at -280px which makes it sit just off screen to the left.

.side-nav {
  background: #333;
  width: 280px;
  height: 100%;
  position: absolute;
  top: 0;
  left: -280px;
}

The .page-content is it's own little container. Set to 100& height and width and the overflow-y set to auto. This makes anything contained in it scroll as it would normally.

.page-content {
  height: 100%;
  width: 100%;
  overflow-y: auto;
  .transition();
  padding: 20px;
}

The .toggle-menu we are going to be using is made of all CSS so we can animated it into a X when the menu is open. This gives the user context as to what to click when the menu is open. The styling of this is beyond the scope of this tutorial, but take a minute to see what is going on here.

.toggle-nav {
  display: block;
  width: 25px;
  position: relative;
  padding: 7px 0;
  .transition();

  span {
    &, &:before, &:after {
      cursor: pointer;
      border-radius: 1px;
      height: 4px;
      width: 25px;
      background: #333;
      position: absolute;
      display: block;
      content: '';
      .transition();
    }

    &:before, &:after {
      .rotate(0);
    }

    &:before {
      top: -7px;
    }

    &:after {
      bottom: -7px;
    }
  }
}

The Javascript

Even though we will be using jQuery to do the off canvas menu, I should note that we are not using it for animation. We are using CSS to animate and only using jQuery to trigger the animation.

var $wrapper = $('.site-wrapper'),
    $openClass = 'show-nav';

$('.toggle-nav').on('click', function() {
  if ($wrapper.hasClass($openClass)) {
    $wrapper.removeClass($openClass);
  } else {
    $wrapper.addClass($openClass);
  }
  return false;
});

What we are doing here is when .toggle-nav is clicked it will toggle the class 'show-nav' on .site-wrapper. Pretty easy and basic.

The Animation

We actually are not doing any animation right now, so lets add that. Since everything depends on the class .show-nav we need to use that in our CSS.

.site-wrapper {
  &.show-nav {
    .site-canvas {
      .translate(280px, 0);
    }
  }
}

If you run that you should now have a nicely animated off canvas menu. The only step now is to animate the .toggle menu into position. We still need to use the class .show-nav because that is our state class to base the animation off of.

.site-wrapper {
  &.show-nav {
    .toggle-nav {
      span {
        background-color: transparent;

        &:before, &:after {
         top: 0;
        }

        &:before {
          .rotate(-45deg);
        }

        &:after {
          .rotate(45deg);
        }
      }
    }
  }
}

Demo

See the Pen mGuBd by Christopher Bishop (@cibgraphics) on CodePen.