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';