Navigation Drawer Pattern With Topcoat CSS Library
Recently I have been playing around with the Topcoat library. Essentially Topcoat is a set of pure CSS-based components for building high performance HTML applications. These apps can be either hosted HTML web apps or native apps packaged with PhoneGap/Cordova. In the app that I’m currently working on I wanted to have a slideable navigation bar that follows the so-called Drawer or Off Canvas UI pattern. Topcoat itself doesn’t come with a built-in implementation of it but all the necessary components are there, so it was just a matter of few lines of CSS and JavaScript to have it running beautifully. In my implementation I also used a simple media query for high-resolution screens like on tablets or desktops where slideable navigation is not necessary.
Below is an example of how it would work on mobile devices. Click a button in the upper left corner to slide it in and out:
Below is an example that will work on high-res screens (to make it work inside an iframe of my blog I had to set the media query to 640px but normally you would probably go for something over 800px). If you are reading this on a mobile device it may still look like the example above; give it a shot on a desktop or on a tablet 😉
Here is a snippet of HTML code with a layout definition:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Topcoat Drawer Example</title> <link rel="stylesheet" type="text/css" href="css/topcoat-mobile-dark.css"> <link rel="stylesheet" type="text/css" href="css/style.css"> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> </head> <body> <div class="topcoat-navigation-bar"> <div class="topcoat-navigation-bar__item left quarter"> <a id="slide-menu-button" class="topcoat-icon-button--quiet slide-menu-button"> <span class="topcoat-icon topcoat-icon--menu-stack"></span> </a> </div> <div class="topcoat-navigation-bar__item center half"> <h1 class="topcoat-navigation-bar__title">Topcoat Drawer</h1> </div> <div class="topcoat-navigation-bar__item right quarter"> <a class="topcoat-icon-button--quiet"> <span class="topcoat-icon topcoat-icon--edit"></span> </a> </div> </div> <nav class="side-nav"> <div class="topcoat-list__container side-nav__list__container"> <ul class="topcoat-list side-nav__list"> <li class="topcoat-list__item side-nav__list__item"> <a href="#" class="side-nav__button">Item</a> </li> <li class="topcoat-list__item side-nav__list__item is-active"> <a href="#" class="side-nav__button">Item</a> </li> <li class="topcoat-list__item side-nav__list__item"> <a href="#" class="side-nav__button">Item</a> </li> </ul> </div> </nav> <div class="main-content"></div> <script src="//use.edgefonts.net/source-sans-pro:n3,n4,n6;source-code-pro:n3.js"></script> <script src="js/main.js"></script> </body> </html>
A bit of JavaScript that controls sliding in and out:
window.onload = function () { var slideMenuButton = document.getElementById('slide-menu-button'); slideMenuButton.onclick = function (e) { var cl = document.body.classList; if (cl.contains('left-nav')) { cl.remove('left-nav'); } else { cl.add('left-nav'); } }; }
Custom CSS code that adds the Drawer/Off Canvas pattern to Topcoat:
html, body { margin:0; padding:0; height: 100%; } body { font-family: source-sans-pro, sans-serif; position: relative; width: 100%; height:100%; overflow: hidden; -webkit-font-smoothing: antialiased; } body.left-nav .topcoat-navigation-bar, body.left-nav .main-content { left:250px; } .topcoat-navigation-bar { position:absolute; width:100%; z-index:100; transition: left 0.2s ease-out; -webkit-transition: left 0.2s ease-out; transform: translate3d(0, 0, 0); -webkit-transform: translate3d(0, 0, 0); } .side-nav { display:block; position:absolute; top:0; left:0; width:320px; height:100%; background-color:#353535; } .side-nav__list__container { margin-top:4rem; border-top:none; border-bottom:none; } .side-nav__list { border-top:none; } .side-nav__list__item { padding:0; } .side-nav__list__item.is-active { background-color:#353535; } .side-nav__button { display:block; width:100%; height:100%; padding: 1.25rem; box-sizing: border-box; color: #c6c8c8; text-decoration:none; } .side-nav__button:hover { background-color:#747474; } .side-nav__button:active { background-color:#353535; } .main-content { position: absolute; background: inherit; left: 0; padding-top:4rem; width:100%; height:100%; transition: left 0.2s ease-out; -webkit-transition: left 0.2s ease-out; transform: translate3d(0, 0, 0); -webkit-transform: translate3d(0, 0, 0); -moz-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.57); -webkit-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.57); box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.57); } @media screen and (min-width: 640px) { /* @media screen and (min-width: 880px) { */ .slide-menu-button { display:none; } .main-content { left:320px; right:0; width:auto; } }
Hey, you forgot to include -moz-box-sizing:border-box to your CSS. As a result, an ugly scroll bar appears in your demo in Firefox. Could you fix that?
Thanks for noticing this, will fix that 😉
Looking good now
Thanks!
This is exactly what I was looking for. Thanks!
I tried your example but it does not display as per your images. Is it possible that you can share your code? Would make our life much better
Hey, it looks like the menu icon does not get displayed with the latest version of Topcoat
With your version of the topcoat css works fine.
Nice tutorial! I find this particularly useful with Snap.js.
Can you post the source code? I can’t get it work. Thanks!
Nice!
There seems to be a hidden button in the top-right corner? (you need to click there to see it). It’s accessible when the draw is closed, and in the iPad version.
That by design or accident?