Simple Responsive nav

by Caleb Wong

HTML

<nav class="responsive-nav" id="js-responsive-nav">
    
    <ul class="responsive-nav__list">
        <li class="responsive-nav__item">
            <a href="http://csswizardry.com/" class="responsive-nav__link">Home</a>
        </li>
        <li class="responsive-nav__item">
            <a href="http://csswizardry.com/about" class="responsive-nav__link">About</a>
        </li>
        <li class="responsive-nav__item">
            <a href="http://csswizardry.com/work" class="responsive-nav__link">Work</a>
        </li>
        <li class="responsive-nav__item">
            <a href="https://twitter.com/csswizardry" class="responsive-nav__link" target="_blank"><b>@csswizardry</b></a>
        </li>
    </ul>
    
</nav>

<h1>Simple Responsive Nav</h1>

<p>An update of <a href="https://twitter.com/csswizardry">@csswizardry's</a> responsive navigation fiddle: <a href="http://jsfiddle.net/csswizardry/ev598/">http://jsfiddle.net/csswizardry/ev598/</a>
</p>

<p>Nav is shown as a stacked list by default. Only when JavaScript is running does it become hidden and visibility is toggled via a button. At larger viewports the nav is displayed horizontally.</p>

<h2>Modifications:</h2>

<ul>
    <li>Changed use of <code>classList</code> object to custom JavaScript functions as browser support is patchy for <code>classList</code> see: <a href="http://caniuse.com/classlist">caniuse.com/classlist</a> (less elegant but more robust).</li>
    <li>Class of ‘js’ is added to the HTML element. It can then be used as a selector in the CSS to define styles only when JavaScript is running.*</li>
    <li>Navigation is available even when JavaScript isn't running.</li>
    <li>No breakpoints need to be declared in the JavaScript – all handled in the CSS.</li>
    <li>Toggle button is added via JavaScript, therefore if it is not running there is automatically no toggle button (menu is shown by default).</li>
    <li>Toggle button is fluid width (but still has min-width) so you can add extra...

SCSS

/* ------------------------------------
  MOBILE FIRST RESPONSIVE NAV
------------------------------------ */

/**
 * VARIABLES
 * =========
*/

$responsive-nav-hit-area:         44px;
$responsive-nav-icon-size:        16px;
$responsive-nav-color:            #fff;
$responsive-nav-background:       #f43059;
$responsive-nav-borders:          lighten($responsive-nav-background, 10%);
$responsive-nav-border-radius:    3px;
$responsive-nav-toggle-text:      "☰";
$responsive-nav-open-toggle-text: "✕";
$responsive-nav-breakpoint:       40em;


/**
 * NAV WRAPPER
 * ===========
 *
 * <nav> element that wraps our navigation.
 *
 * [1] Make sure we can’t actually see the absolutely positioned dropdown.
*/

.responsive-nav {

	position: relative;
	max-width: 20em;
	overflow: hidden; // [1]

	/* Now show full width */
	@media (min-width: 40em) {
		max-width: 100%;
	}

}

/* Class added via JS when toggled open */
.responsive-nav--open {
	overflow: visible; // allow dropdown to be seen
}


/**
 * NAV LIST
 * ========
*/

.responsive-nav__list {

	list-style: none;
	margin:  0;
	padding: 0;
	background-color: $responsive-nav-background;
	border-bottom-right-radius: $responsive-nav-border-radius;
	border-bottom-left-radius: $responsive-nav-border-radius;
	width: 100%;

	/**
	 * Hide nav by default only when JS is running and viewport is less than
	 * navigation breakpoint.
	 * The wrapper has 'overflow: hidden;' which hides it.
	*/
	@media (max-width: 40em) {
		.js & {
			position: absolute;
		}
	}

	/* Remove background */
	@media (min-width: 40em) {
		background: none;
	}

}


/**
 * NAV LIST ITEMS
 * ==============
*/

.responsive-nav__item {

	border-top: 1px solid $responsive-nav-borders;

	/* Change from stacked to display in a row */
	@media (min-width: 40em) {
		display: inline-block;
		border-top: none; // separator no longer needed
	}

}


/**
 * NAV LINKS
 * =========
 *
 * [1] Ensure that the link text lines up with the hamburger.
 * [2] Ensure that the link text is...

JavaScript

/**
 * RESPONSIVE NAV JS
 * =================
*/

/* The target nav */
var responsiveNav = document.getElementById('js-responsive-nav');

/* Insert <a> element for toggle button inside the <nav> element */
var toggleBtn = document.createElement('a');
toggleBtn.setAttribute('href', '#');
toggleBtn.setAttribute('class', 'responsive-nav__toggle');
responsiveNav.insertBefore(toggleBtn, responsiveNav.firstChild);

/* Has Class Function */
function hasClass(e,t){return(new RegExp(' '+t+' ')).test(' '+e.className+' ')}

/* Toggle Class Function */
function toggleClass(e,t){var n=' '+e.className.replace(/[\t\r\n]/g,' ')+' ';if(hasClass(e,t)){while(n.indexOf(' '+t+' ')>=0){n=n.replace(' '+t+' ',' ')}e.className=n.replace(/^\s+|\s+$/g,'')}else{e.className+=' '+t}}

/* Toggle 'responsive-nav--open' when button is clicked */
toggleBtn.onclick = function() {
    toggleClass(this.parentNode, 'responsive-nav--open');
}

/* Add a class of 'js' to the HTML element */
var root = document.documentElement;
root.className = root.className + ' js';