Step 5: Adding and stylizing the menu contents
For the menu contents, we'll go with the trend of showing only essential navigational links, instead of stuffing it with everything except the kitchen sink. Remember, on a mobile device, there is very limited space for superfluous additions. We'll also add a prominent "close" button inside it to easily dismiss the menu. Lets see the result:
Menu contents CSS
nav#offcanvas-menu label#closex{ /* Large x close button inside nav */ width: 50px; height: 50px; overflow: hidden; display: block; position: absolute; cursor: pointer; text-indent: -1000px; z-index: 10; top: 0; right: 0; } nav#offcanvas-menu label#closex::before, nav label#closex::after{ /* render large cross inside close button */ content: ""; display: block; position: absolute; width: 100%; height: 6px; background: black; top: 50%; margin-top: -3px; transform: rotate(-45deg); } nav#offcanvas-menu label#closex::after{ /* render large cross inside close button */ transform: rotate(-135deg); } nav#offcanvas-menu a{ text-decoration: none; color: black; text-transform: uppercase; } nav#offcanvas-menu ul{ list-style: none; margin-top: 200px; opacity: 0; padding: 0; position: relative; font: bold 1.5em 'Bitter', sans-serif; /* use google font inside nav UL */ transition: margin-top 0.2s 0.3s, opacity 0.5s 0.3s; } nav#offcanvas-menu ul li{ margin-bottom: 25px; } nav#offcanvas-menu ul li a{ padding: 10px; border-radius: 20px; } nav#offcanvas-menu ul li a:hover{ background: lightblue; } input[type="checkbox"]#togglebox:checked ~ nav#offcanvas-menu ul{ /* nav state when corresponding checkbox is checked */ margin-top: 100px; opacity: 1; }
Menu contents markup
<nav id="offcanvas-menu"> <label for="togglebox" id="closex">Close</label> <ul> <li><a href="http://www.javascriptkit.com">Home</a></li> <li><a href="http://www.javascriptkit.com/cutpastejava.shtml">JavaScripts</a></li> <li><a href="http://www.javascriptkit.com/javatutors">JS Tutorials</a></li> <li><a href="http://www.dynamicdrive.com/style/">CSS Library</a></li> <li><a href="http://www.dynamicdrive.com/forums/">Forums</a></li> <li><a href="http://www.cssdrive.com">CSS Gallery</a></li> </ul> </nav>
Live Demo:
Lets focus our attention on the large "close" button first. Markup wise
it's implemented as a label for the #togglebox
checkbox element; that's the beauty of
using CSS checkboxes to control the state of sibling elements- we can
implement as many and as varied corresponding labels as we want to do its
bidding. For the button's style, we use CSS :before
and :after
psuedo
elements to create two black stripes, each rotated by a certain amount to
form the large "x" look.
For the main menu UL element, the goal is to have it animate up into view
when the parent off-canvas menu is opened to create a subtle easing effect.
For that we animate the "margin-top
" and "opacity
" properties of the UL
after a 0.3s delay whenever the checkbox is toggled.
Finally, for the UL's font, we chose a custom Google font called "Bitter", by adding the following external stylsheet to the HEAD section of the page:
<link href="http://fonts.googleapis.com/css?family=Bitter&subset=latin" rel="stylesheet" type="text/css">
plus the following value inside the "font" property of the UL selector:
font: bold 1.5em 'Bitter', sans-serif; /* use google font inside nav UL */
Step 6: Adding an overlay to the page when the off-canvas menu is open
A common UI addition to lightbox and custom modal windows, an overlay is a semi opaque element that covers the entire page while an effect is active, forcing the user's attention on a specific element. Coming up next, we'll add an overlay for our off-canvas menu that not only does that, but provides users an additional way to dismiss the menu, by clicking on the overlay.
To create the overlay, we'll use a DIV element that's fixed in position
and spans the entire page, but with a z-index
value lower than the
off-canvas menu's for obvious reasons. And how do we go about making the
entire overlay act as a toggler for dismissing the menu when users click on
it? The answer if you haven't already guessed it starts with a "L"- by
embedding a label inside it of course. Once again the versatility of using
the checkbox sibling technique to control the state of our menu is
illustrated; with such a central event control scheme in place, we can spawn
corresponding labels of all shapes and sizes to trigger the event at will.
Lets now see the CSS and markup for the overlay element:
Overlay element CSS:
div.overlay { /* overlay that covers entire page when menu is open */ position: fixed; width: 100%; height: 100%; left: 0; top: 0; opacity: 0; background: black; z-index: 99; visibility: hidden; transition: opacity 0.5s; /* transition settings */ } div.overlay label { /* label of overlay that closes menu when clicked on */ width: 100%; height: 100%; position: absolute; } input[type="checkbox"]#togglebox:checked ~ div.overlay{ /* overlay state when corresponding checkbox is checked */ opacity: 0.6; visibility: visible; }
Overlay element markup:
<!doctype html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> /* Menu styles added here */ </style> </head> <body> <input type="checkbox" id="togglebox" /> <div class="overlay"><label for="togglebox"></label></div> <nav id="offcanvas-menu"> <label for="togglebox" id="closex">Close</label> <ul> <li><a href="http://www.javascriptkit.com">Home</a></li> <li><a href="http://www.javascriptkit.com/cutpastejava.shtml">JavaScripts</a></li> <li><a href="http://www.javascriptkit.com/javatutors">JS Tutorials</a></li> <li><a href="http://www.dynamicdrive.com/style/">CSS Library</a></li> <li><a href="http://www.dynamicdrive.com/forums/">Forums</a></li> <li><a href="http://www.cssdrive.com">CSS Gallery</a></li> </ul> </nav> <div id="contentarea"> <label for="togglebox" id="navtoggler">Menu</label> Some body content here some body content here </div> </body> </html>
Live Demo:
The location of the overlay DIV in the source code is important in that it
should follow the #togglebox
checkbox element as a sibling, similar to the
off-canvas menu and #contentarea
DIV. This way, we can control the overlay
DIV's visibility based on the checked state of the checkbox by using the
checkbox sibling selector:
input[type="checkbox"]#togglebox:checked ~ div.overlay{ /* overlay state when corresponding checkbox is checked */ opacity: 0.6; visibility: visible; }
Also, notice how we've embedded a LABEL element inside the overlay DIV that covers the entire DIV. This is how we get the overlay to dismiss the off-canvas menu upon clicking on it.
Ok, we've come a long way and now have a functional off-canvas menu in all modern browsers (IE9+ with no content shifting effect, and all other modern browsers) without a trace of JavaScript so far. However, with just a little help from the nifty language, we can take the menu to a new level, by extending the menu's compatibility to IE8, as well as be able to control the state of the menu on demand instead of just via HTML labels. It's worth the extra code, trust us.
- Creating an off-canvas side menu using CSS3 (and a touch of JavaScript)
- Next steps- stylizing the menu contents and adding an overlay when the menu is open
- Using JavaScript to toggle the menu on demand, create IE8 compatibility
Using JavaScript to toggle the menu on demand, create IE8 compatibility