Mobile Menu

This implementation uses classList which is not fully supported in all browsers (stupid IE). If you need it, you should pull in the the polyfill.

Markup

<div class="SiteContainer">

    <!--
        We keep our mobile menu as the top most element
        to make it easier to keep off canvas
    -->
    <nav class="Nav Nav--mobile" aria-hidden="true">
        
        <ul id="menu-main-menu" class="menu">
            <li id="menu-item-22" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22">
                <a href="https://objectiv.co/work/" itemprop="url">Work</a>
            </li>
            <li id="menu-item-21" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-21">
                <a href="https://objectiv.co/services/" itemprop="url">Services</a>
            </li>
            <li id="menu-item-23" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23">
                <a href="https://objectiv.co/our-story/" itemprop="url">Our Story</a>
            </li>
            <li id="menu-item-3617" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-3617">
                <a href="https://store.objectiv.co" itemprop="url">Plugins</a>
            </li>
            <li id="menu-item-20" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20">
                <a href="https://objectiv.co/blog/" itemprop="url">Blog</a>
            </li>
            <li id="menu-item-19" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-19">
                <a href="https://objectiv.co/contact/" itemprop="url">Contact</a>
            </li>
        </ul>

    </nav>
    
    <div class="SiteHeader" role="banner" itemscope itemtype="http://schema.org/WPHeader">
    
        <h1 class="SiteTitle" itemscope itemtype="http://schema.org/Organization">
            <a  itemprop="url" href="#" rel="home">
                <img itemprop="logo" class="Logo" src="https://placehold.it/140x40?text=LOGO" height="42" width="140" alt="">
                <!--
                    Visually hide this text.
                    WCAG 2.0: “image alt text cannot be the primary text of a link"
                -->
                <span class="screen-reader-text">Objectiv</span>
            </a>
        </h1>
    
        <button class="NavToggle" aria-expanded="false">
            <div class="NavToggle-icon">
                <span></span>
                <span></span>
                <span></span>
                <span></span>
            </div>
            <span class="screen-reader-text">Primary Menu</span>
        </button>
    
    </div>

</div>

Styles

CSS

body {
    margin: 0;
    padding: 0;
}

.screen-reader-text {
    clip: rect(1px, 1px, 1px, 1px);
    position: absolute !important;
    height: 1px;
    width: 1px;
    overflow: hidden;
}

.SiteContainer {
    position: relative;
    right: 0;
    transition: all 0.5s ease-in-out;
}

.SiteContainer.Nav--is-visible {
    right: 300px;
}

.SiteHeader {
    align-items: center;
    background: #555;
    display: flex;
    padding: 10px;
}

.SiteTitle {
    margin: 0;
}

.Logo {
    display: block;
}

.NavToggle {
    background: none;
    border: none;
    color: #fff;
    font-size: 18px;
    margin-left: auto;
}

.NavToggle-icon {
    height: 12px;
    position: relative;
    transform: rotate(0deg);
    transition: all 0.25s ease-in-out;
    width: 20px;
}

.NavToggle-icon span {
    display: block;
    position: absolute;
    height: 2px;
    width: 100%;
    background: #fff;
    border-radius: 0;
    opacity: 1;
    left: 0;
    transform: rotate(0deg);
    transition: all 0.25s ease-in-out;
}

.NavToggle-icon span:nth-child(1) {
    top: 0px;
}

.NavToggle-icon span:nth-child(2),
.NavToggle-icon span:nth-child(3) {
    top: 5px;
}

.NavToggle-icon span:nth-child(4) {
    top: 10px;
}

.NavToggle.Nav--is-visible .NavToggle-icon span:nth-child(1) {
    opacity: 0;
}

.NavToggle.Nav--is-visible .NavToggle-icon span:nth-child(2) {
    transform: rotate(45deg);
}

.NavToggle.Nav--is-visible .NavToggle-icon span:nth-child(3) {
    transform: rotate(-45deg);
}

.NavToggle.Nav--is-visible .NavToggle-icon span:nth-child(4) {
    left: 50%;
    top: 18px;
    width: 0%;
}

.Nav {
    transition: all 0.5s ease-in-out;
}

.Nav .menu {
    margin: 0;
    padding: 15px 0;
}

.Nav .menu .menu-item {
    list-style: none;
}

.Nav .menu .menu-item > a {
    color: #fff;
    display: block;
    padding: 10px 20px;
    text-decoration: none;
}

.Nav--mobile {
    background-color: #2d2d2d;
    height: 100%;
    overflow: auto;
    position: fixed;
    right: -300px;
    top: 0;
    width: 300px;
    z-index: 2000;
}

.Nav--mobile.Nav--is-visible {
    right: 0;
}

.SiteContainer.Nav--is-visible {
    right: 300px;
}

Sass


Javascript

Plugin

/**
 * Objectiv Mobile Menu
 */
(function() {
    'use strict';

    if ('object' !== typeof window.Objectiv) {
        window.Objectiv = {};
    }

    window.Objectiv.mobileMenu = function(options) {
        if ('undefined' === typeof options.menu)
            return false;

        var container = document.querySelector(options.container),
            menu = document.querySelector(options.menu),
            toggle = document.querySelector(options.toggle);

        if (!container || !menu || !toggle) return;

        function toggleMenu() {
            container.classList.toggle('Nav--is-visible');
            menu.classList.toggle('Nav--is-visible');
            toggle.classList.toggle('Nav--is-visible');

            if (toggle.classList.contains('Nav--is-visible')) {
                toggle.setAttribute('aria-expanded', true);
                menu.setAttribute('aria-hidden', false);
            } else {
                toggle.setAttribute('aria-expanded', false);
                menu.setAttribute('aria-hidden', true);
            }
        }

        toggle.addEventListener('click', function(e) {
            e.preventDefault();
            toggleMenu();
        });  
    }
})();

Usage

Objectiv.mobileMenu({
    container: '.SiteContainer',
	menu: '.Nav--mobile',
    toggle: '.NavToggle'
});