Project: Off-canvas menu

Project: Off-canvas menu

In this lesson, we will create an off-canvas menu in javascript.

0:00
/0:04

So, what is an off-canvas menu?

It is nothing but a secret menu that is positioned outside of the visible portion of the screen.

And when the menu button is clicked, the off-canvas content will be pushed into the visible portion of the screen.

And when the menu button is clicked again, it will be pushed off the screen so that it becomes hidden again.

Usually, the Off-canvas pattern is implemented for mobile devices to save some screen space and keep things organized.

But sometimes, it is used for serving desktop users as well.

It is totally a design preference.

Anyway, let's quickly implement it.

The starter files

Download the project starter files and open the project inside your code editor.

And here is the project structure:

.
└── ai-art-starting-files/
    ├── images/
    │   ├── bars-solid.svg
    │   ├── open-theatre.png
    │   ├── watering-robot.png
    │   └── ...
    ├── index.html
    ├── style.css
    └── index.js

The HTML

If you open up the index.html file, it already has the HTML markup for implementing the off-canvas functionality.

<body>
    <div id="off-canvas-content">
        <!-- ... -->
    </div>
    <div id="page-content">
        <button class="menu-toggle">
            <!-- ... -->
        </button>
        <div id="main-content">
            <!-- ... -->
        </div>
    </div>
    <script src="index.js"></script>
</body>

If you notice, the <body> element has two elements.

  1. #off-canvas-content element that holds the off-canvas menu
  2. #page-content element that holds the content of the page with the menu button

The CSS

The style.css file contains the basic styling for the #page-content only.

The initial preview

If you notice, the #off-canvas-content element is not styled at all.

Also, it must be positioned outside the visible screen, right?

So, let's style it and position it off the screen

#off-canvas-content{
    width:20rem;
    background-color:#E2F1F8;
    padding:40px;
    position:absolute;
    left:-20rem;
    top:0;
    bottom:0;
    box-sizing: border-box;
    transition: all 0.3s ease-in;
}
nav ul, nav li{
    list-style: none;
    padding:0;
    margin:0;
}
nav li{
    margin-bottom:10px;
}
nav a{
    text-decoration: none;
}

Add the above CSS to the end of the style.css file.

Apart from some basic list styling, it is basically making the #off-canvas-content positioned absolutely so that it can be pushed off the screen using left:-20rem.

Everything is now set.

But when we click on the menu button, nothing happens.

Our goal

  1. When the menu button is clicked, the off-canvas content should be pushed into the visible portion of the screen.
  2. And then when the button is clicked again, the off-canvas content should be pushed off the visible portion of the screen.

And here is the javascript that helps achieve our goal:

//Select the Menu button
const menuToggleButton = document.querySelector(".menu-toggle");

//Add event listener to it
menuToggleButton.addEventListener("click", function(){
    document.body.classList.toggle("off-canvas-is-open");
});

Add it to the end of the index.js file.

You already know what's happening here.

First, we are selecting the menu button and then we are adding a click event listener to it.

And every time the menu button is clicked, we are toggling the class "off-canvas-is-open" on the <body> element.

💡
You don't have to manually select the <body> element using the querySelector() method. You can directly access it using the document.body. This facility is only applicable to the <body> element.
document.body.classList.toggle("off-canvas-is-open");

Anyway, the idea here is:

  1. When the class "off-canvas-is-open" is added to the <body> element, the off-canvas content should be pushed inside the screen.
  2. When we remove the class, the off-canvas content should be pushed off the screen again.

And, here is the supporting CSS that pushes the #off-canvas-content into the screen when the "off-canvas-is-open" class is added to the <body> element:

.off-canvas-is-open #off-canvas-content,
.off-canvas-is-open #page-content{
    transform: translateX(20rem);
}

Using the transform property is the easiest way to push the HTML elements.

Add it to the end of the style.css file.

If you now, open up the browser, you should the functionality working as expected:

0:00
/0:04

Just to be on the same page, here is how everything works together

The initial state

When the index.html is initially loaded, the class "off-canvas-is-open" is not present on the <body>, tag.

So, the #off-canvas-content stays outside the screen.

But when the button was clicked for the first time

The class "off-canvas-is-open" will be added to the <body> element.

0:00
/0:03

And it will trigger the following CSS:

.off-canvas-is-open #off-canvas-content,
.off-canvas-is-open #page-content{
    transform: translateX(20rem);
}

This results in the following:

  1. Off-canvas content is being pushed into the visible portion of the screen.
  2. The page content will be pushed slightly, too.

Finally, when the button clicked again...

The class "off-canvas-is-open" will be removed from the <body> element using Javascript:

menuToggleButton.addEventListener("click", function(){
    document.body.classList.toggle("off-canvas-is-open");
});
0:00
/0:04

It makes the following CSS no longer applicable:

.off-canvas-is-open #off-canvas-content,
.off-canvas-is-open #page-content{
    transform: translateX(20rem);
}

So, this results in the following:

  1. Off-canvas content is being pushed outside of the visible portion of the screen.
  2. The page content will be pushed back to its original position.

That's all.

Easy, right?

In the next lesson, we will learn about passing parameters to custom functions.