Creating a double off-canvas menu can greatly enhance the user experience by providing accessible navigation options without occupying valuable screen space. This article will guide you through how I built a double off-canvas menu using CSS and JavaScript. The menu will feature two “drawer” menus that open from the left and right sides of the screen.
This feature has been used in one of my WordPress themes — Supernova — to allow more content to be readily available. Inside each menu lies a Pattern, which can contain anything, from a navigation menu to a custom query loop or to a shortcode.
A WordPress pattern is a collection of blocks arranged together into a thoughtful, intentional, opinionated section for a page or post. Once inserted into a page, the author can edit and customize the blocks to their needs.
https://wordpress.org/patterns/about/
HTML Structure
Start by setting up the basic HTML structure for your off-canvas menus. We’ll use checkboxes to control the opening and closing of the menus, and labels to act as the toggles.
Clicking on the “LEFT MENU” and “RIGHT MENU” labels will slide the respective menus in and out of view.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Double Off-Canvas Menu</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<input type="checkbox" id="supernova-drawer--toggle-left">
<input type="checkbox" id="supernova-drawer--toggle-right">
<div class="page-wrap">
<label for="supernova-drawer--toggle-left" class="supernova-drawer--left-toggle">LEFT MENU</label>
<label for="supernova-drawer--toggle-right" class="supernova-drawer--right-toggle">RIGHT MENU</label>
<div class="supernova-drawer--left">
Hello from the left side!
</div>
<div class="supernova-drawer--right">
Hello from the right side!
</div>
</div>
<script src="scripts.js"></script>
</body>
</html>
CSS Styling
Next, let’s style the off-canvas menus and their toggles. We’ll define the appearance and behaviour using CSS variables and transitions. I have used a CSS variable to define the width, as this is a value that I will use frequently throughout the code, and changing it in one place is faster.
For the menu opening animation, I have used Bezier easeOutCirc easing:
cubic-bezier(0, 0.55, 0.45, 1)
:root {
--drawer-width: 400px;
}
* {
box-sizing: border-box;
}
.supernova-drawer--left-toggle,
.supernova-drawer--right-toggle {
display: inline-block;
padding: 24px 16px;
background-color: #333333;
color: #ffffff;
font-size: 18px;
transition: all 0.4s cubic-bezier(0, 0.55, 0.45, 1);
position: absolute;
top: 50%;
z-index: 32;
writing-mode: vertical-lr;
text-orientation: mixed;
transform: translateY(-50%);
}
.supernova-drawer--left-toggle {
left: 0;
}
.supernova-drawer--right-toggle {
right: 0;
}
#supernova-drawer--toggle-left,
#supernova-drawer--toggle-right {
display: none;
}
.supernova-drawer--left.open,
.supernova-drawer--right.open {
transform: translateX(0);
}
.supernova-drawer--left-toggle.open {
transform: translateX(var(--drawer-width)) translateY(-50%);
}
.supernova-drawer--right-toggle.open {
transform: translateX(calc(var(--drawer-width) * -1)) translateY(-50%);
}
.supernova-drawer--left,
.supernova-drawer--right {
position: fixed;
top: 0;
bottom: 0;
width: var(--drawer-width);
padding: 2em;
z-index: 32;
transition: transform 0.4s cubic-bezier(0, 0.55, 0.45, 1);
}
.supernova-drawer--left {
left: 0;
transform: translateX(-100%);
background: #eeeeee;
}
.supernova-drawer--right {
right: 0;
transform: translateX(var(--drawer-width));
background: #dddddd;
}
JavaScript Functionality
Finally, let’s add the JavaScript to handle the toggling of the menus. This script will listen for click events on the checkboxes and toggle the open
class on the corresponding elements.
// Add an event listener to the checkbox with the ID 'supernova-drawer--toggle-left'
document.getElementById('supernova-drawer--toggle-left').addEventListener('click', () => {
// Toggle the 'open' class on the label for the left menu toggle
document.querySelector('.supernova-drawer--left-toggle').classList.toggle('open');
// Toggle the 'open' class on the left drawer menu
document.querySelector('.supernova-drawer--left').classList.toggle('open');
});
// Add an event listener to the checkbox with the ID 'supernova-drawer--toggle-right'
document.getElementById('supernova-drawer--toggle-right').addEventListener('click', () => {
// Toggle the 'open' class on the label for the right menu toggle
document.querySelector('.supernova-drawer--right-toggle').classList.toggle('open');
// Toggle the 'open' class on the right drawer menu
document.querySelector('.supernova-drawer--right').classList.toggle('open');
});
Demo
See the Pen Untitled by Ciprian (@ciprian) on CodePen.