Old vintage compass and navigation instruments on ancient map

How to create an off-canvas navigation menu with CSS

Popularized by apps like Facebook on mobile, the off canvas menu allows to save valuable real screen estate by toggling the navigation into view only when needed. We will dive and explore one way of achieving the effect using some overlooked CSS properties.

Goals and Challenges

  1. Create additional screen real estate by hiding the navigation
  2. Easily access the menu via clicking off canvas icon and having it slide into place
  3. Only CSS will be used for the effect
  4. Support a many browsers as possible

The markup

Starting with a wrapper div, we will use some of the new HTML5 elements to host the two main elements : the navigation and the content


We will then wrap the main content in a section tag

The container div is not really necessary and is the result of my habit of coding responsive sites, which we'll do a little of - just enough to stay within the scope.


I have kept the CSS inline to keep it concise but it can easily be part of an external script.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
html {
  font-size: 63.5%;
  font-family: "Roboto Slab", serif;
  height: 100%;
body {
  font-size: 1.6rem;
  line-height: 2.8rem;
  height: 100%;
.wrapper {
  height: 100%;
.container {
  margin: 0 15px;
.row {
  padding: -15px;
  margin: 15px 0;
.row:after {
  content: "";
  display: table;
nav li {
  padding: 8px;

Now that we have the initial styles in place let's take care of the two main elements.
So for the sidebar we will set an initial width of 40%, float it to the left and position it off the screen with a margin-left of -40%, also we'll add a position absolute to avoid having it stacked on the main content.

aside {
  background-color: #333;
  color: #fff;
  width: 40%;
  margin-left: -40%;
  float: left;
  height: 100%;
  position: absolute;

Now for the section element that houses the main content we will float it to the right with a width and height of 100% and a margin-right of 0.

section {
  width: 100%;
  height: 100%;
  float: right;
  margin-right: 0;

The Toggle

Now lets' add a checkbox at the top of our markup just before the wrapper div.

We gave it and id of offcanvas this will be used later by labels to trigger the toggle. 

Now we essentially want to react to the checked state of the input and bring the navigation to view when checked and hide again when uncheked.

We will use the adjacent selector in our CSS and target the aside element first

.toggle:checked + .wrapper > aside {
  margin-left: 0;

and the same for the section element

.toggle:checked + .wrapper > section {
  margin-right: -40%;

Make It Pretty

The main goal of hiding and showing the navigation has already been taken care of. We will just make it a little nicer by adding the infamous "hamburger" button and make the transition smooth.

Let's add a label that will contain the button and that will trigger the toggle. At the top of the section element let add this code:

The label for attribute has a value of offcanvas which is the same as the id of our input button.

This allow us to trigger the toggle from anywhere on the page where the label code exist. Now let's add some styles

.toggler {
  display: inline-block;
  cursor: pointer;
.navicon {
  width: 28px;
  height: 28px;
  background: url("navicon.png") no-repeat;
  background-size: cover;
  display: block;

We can now hide the input button

.toggle { display: none; }

A Big Hit

When the navigation is in view the only way to hide it again is by precisely hitting the menu button.

This might be ok on a desktop screen but can be challenging on smaller resolutions.

We will make the entire content clickable during that state to alleviate that issue.

So back to the html before the first label we will add another one

We gave it a class of biglabel. In our CSS we will hide it when the navigation is hidden and have it cover the entire content as a big button.

.biglabel {
  display: none;
.biglabel {
  width: 100%;
  height: 100%;
  position: absolute;
  cursor: pointer;
.toggle:checked + .wrapper > section .biglabel {
  display: block;

When we refresh the browser we can see now that the entire content becomes clickable when the navigation is in view. Perfect!! Well almost.

Smooth Like a Moonwalker

The last step is to handle the transition and make the navigation slide in nicely.

Using CSS3 transition makes it very easy. We will target both the sidebar and the main content

section {
  -webkit-transition: margin 0.5s ease-in-out;
  -moz-transition: margin 0.5s ease-in-out;
  -ms-transition: margin 0.5s ease-in-out;
  -o-transition: margin 0.5s ease-in-out;
  transition: margin 0.5s ease-in-out;

And Voila!! Our menu now kicks out nicely the content when coming to view and leaves without a noise.

Hopefully you found it useful and enjoyed it as much as I did. Please share and let me know your thoughts in the comments.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.