Categories:

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.

Using JavaScript to toggle the menu on demand, create IE8 compatibility