On this tutorial, we’ll undergo a easy but efficient technique for making a responsive off-canvas menu with HTML, CSS, and JavaScript.
To get an preliminary thought of what we’ll be constructing, check out the associated CodePen demo (try the bigger model to see how the structure adjustments):
1. Start With Markup
Our markup will encompass two wrapper parts:
- the
.top-banner
factor - the
.top-nav
factor
Right here’s the HTML code:
1 |
<part class="top-banner"> |
2 |
<div class="top-banner-overlay"> |
3 |
<!-- content material right here -->
|
4 |
</div>
|
5 |
</part>
|
6 |
|
7 |
<nav class="top-nav"> |
8 |
<div class="menu-wrapper"> |
9 |
<!-- content material right here -->
|
10 |
</div>
|
11 |
<div class="fixed-menu"> |
12 |
<!-- content material right here -->
|
13 |
</div>
|
14 |
</nav>
|
2. Subsequent We Want Some CSS
With the markup prepared, subsequent let’s study crucial kinds that are required for our menu.
information
For the sake of readability, this CSS code isn’t optimized—you’ll discover duplicate properties which you will wish to strip out in your individual model.
Styling the top-banner Factor
The .top-banner
factor will appear to be this:
Relating to its kinds, we’ll do the next:
- Set its width equal to the window width minus the width of the
.fixed-menu
factor. - Set its peak equal to the window peak.
- Outline it as a flex container. This may pressure its overlay to cowl the total dad or mum peak.
- Use flexbox to vertically middle the overlay’s content material.
Listed here are the kinds we’ll want to realize all that:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.top-banner { |
4 |
place: relative; |
5 |
left: 150px; |
6 |
show: flex; |
7 |
width: calc(100% - 150px); |
8 |
peak: 100vh; |
9 |
background: url(IMAGE_PATH) no-repeat middle / cowl; |
10 |
}
|
11 |
|
12 |
.top-banner-overlay { |
13 |
show: flex; |
14 |
flex-direction: column; |
15 |
justify-content: middle; |
16 |
width: 350px; |
17 |
padding: 20px; |
18 |
transition: all .7s; |
19 |
colour: var(--white); |
20 |
background: rgba(0, 0, 0, .7); |
21 |
}
|
Styling the .top-nav
Factor
The .top-nav
factor will appear to be this:
On this case, we’ll do the next:
- Specify the direct baby parts as fastened positioned parts that can cowl the window peak.
- Use flexbox to vertically align the
.fixed-menu
factor. - Conceal the
.menu-wrapper
factor by default. To take action, we can’t give it a property worth resemblingshow: none
. In actual fact, we’ll use thetranslate()
operate to maneuver it 200px to the left. Take into account that the factor’s width is 350px, so a part of it is going to nonetheless be inside the viewport. Nevertheless, it will not be seen as a result of the factor is positioned beneath the.fixed-menu
factor. - Conceal the menu record.
Take a look on the corresponding CSS kinds under:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.top-nav .menu-wrapper { |
4 |
place: fastened; |
5 |
prime: 0; |
6 |
left: 0; |
7 |
backside: 0; |
8 |
width: 350px; |
9 |
padding: 20px; |
10 |
remodel: translateX(-200px); |
11 |
transition: remodel .7s; |
12 |
background: var(--menu-color); |
13 |
}
|
14 |
|
15 |
.top-nav .menu-wrapper .menu { |
16 |
opacity: 0; |
17 |
transition: opacity .4s; |
18 |
}
|
19 |
|
20 |
.top-nav .fixed-menu { |
21 |
place: fastened; |
22 |
prime: 0; |
23 |
left: 0; |
24 |
backside: 0; |
25 |
show: flex; |
26 |
flex-direction: column; |
27 |
width: 150px; |
28 |
padding: 20px; |
29 |
background: var(--fixed-menu-color); |
30 |
}
|
3. Now for Some JavaScript
At this level, we’ll use some easy JavaScript code to control the state of the off-canvas menu.
Toggle Menu
We will toggle the menu within the following methods:
- Every time we click on on the
.menu-toggle
button, the menu’s visibility will change. If it’s hidden, it’ll seem with a pleasant slide-in impact, and the overlay will likely be pushed concurrently to the best. Optionally, we will do much more issues throughout this state. In our instance, we’ll add a field shadow to the::earlier than
pseudo-element of the overlay and reveal the menu record utilizing a fade-in impact. Quite the opposite, if the menu is seen, it will disappear with a slide-out impact, and the overlay will likely be pushed concurrently to the left.
- One other attainable technique to shut the menu is thru the
.menu-close
button that’s a part of the.menu-wrapper
factor. - By default, we will additionally toggle the menu via the keyboard by focusing the toggle buttons and urgent the
Enter
orTab
keys. We’ll additionally add a situation for closing the menu by urgent theEsc
key.
Right here’s the JavaScript code which implements this conduct:
1 |
const topNav = doc.querySelector(".top-nav"); |
2 |
const menuToggle = topNav.querySelector(".menu-toggle"); |
3 |
const menuClose = topNav.querySelector(".menu-close"); |
4 |
const menuWrapper = topNav.querySelector(".menu-wrapper"); |
5 |
const topBannerOverlay = doc.querySelector(".top-banner-overlay"); |
6 |
const isOpenedClass = "is-opened"; |
7 |
const isMovedClass = "is-moved"; |
8 |
|
9 |
menuToggle.addEventListener("click on", () => { |
10 |
menuWrapper.classList.toggle(isOpenedClass); |
11 |
topBannerOverlay.classList.toggle(isMovedClass); |
12 |
});
|
13 |
|
14 |
menuClose.addEventListener("click on", () => { |
15 |
menuWrapper.classList.take away(isOpenedClass); |
16 |
topBannerOverlay.classList.take away(isMovedClass); |
17 |
});
|
18 |
|
19 |
doc.addEventListener("keydown", (e) => { |
20 |
if (e.key == 'Escape' && menuWrapper.classList.accommodates(isOpenedClass)) { |
21 |
menuClose.click on(); |
22 |
}
|
23 |
});
|
And under you’ll discover the related CSS kinds:
1 |
.top-banner-overlay.is-moved { |
2 |
remodel: translateX(350px); |
3 |
}
|
4 |
|
5 |
.top-banner-overlay.is-moved::earlier than { |
6 |
content material: ""; |
7 |
place: absolute; |
8 |
prime: 0; |
9 |
backside: 0; |
10 |
proper: 100%; |
11 |
width: 20px; |
12 |
box-shadow: 3px 0 10px rgba(0, 0, 0, .75); |
13 |
}
|
14 |
|
15 |
.top-nav .menu-wrapper.is-opened { |
16 |
remodel: translateX(150px); |
17 |
}
|
18 |
|
19 |
.top-nav .menu-wrapper.is-opened .menu { |
20 |
opacity: 1; |
21 |
transition-delay: .6s; |
22 |
}
|
4. Going Responsive
At this level, we’ll study make our off-canvas responsive.
When the viewport is as much as 900px:
- The highest banner may have a peak equal to the window peak minus the peak of the
.fixed-menu
factor. - The highest banner overlay will cease having the window peak—it will be vertically centered contained in the banner.
- Additionally, the fastened header will cease having the window peak. In actual fact, it will have a hard and fast peak of 50px.
- The navigation structure will change to horizontal.
- The menu will likely be full-screen and proceed to be off-screen by default.
- Upon menu toggle click on, the banner overlay will likely be moved off-screen to the best.
Alternatively, holding the banner overlay all the time on the display and overlapping the menu whereas in view can also be an choice. Remark out the properties under marked with the quantity 2 and run the pen to see the distinction.
As we’re utilizing a desktop-first strategy, these are crucial kinds that we’ve got so as to add/overwrite:
1 |
@media (max-width: 900px) { |
2 |
physique { |
3 |
font-size: 16px; |
4 |
overflow-x: hidden; |
5 |
}
|
6 |
|
7 |
.top-banner { |
8 |
prime: 50px; |
9 |
left: auto; |
10 |
width: 100%; |
11 |
peak: calc(100vh - 50px); |
12 |
remodel: none; |
13 |
align-items: middle; |
14 |
}
|
15 |
|
16 |
.top-banner-overlay { |
17 |
place: relative; /*2*/ |
18 |
left: 0; /*2*/ |
19 |
max-width: 100%; |
20 |
}
|
21 |
|
22 |
.top-banner-overlay.is-moved { |
23 |
left: 100%; /*2*/ |
24 |
remodel: none; |
25 |
}
|
26 |
|
27 |
.top-nav .menu-wrapper { |
28 |
width: 100%; |
29 |
remodel: translateX(-100%); |
30 |
padding-top: 70px; |
31 |
}
|
32 |
|
33 |
.top-nav .menu-wrapper.is-opened { |
34 |
remodel: none; |
35 |
}
|
36 |
|
37 |
.top-nav .menu-wrapper .menu-close { |
38 |
prime: 70px; |
39 |
}
|
40 |
|
41 |
.top-nav .fixed-menu { |
42 |
backside: auto; |
43 |
flex-direction: row; |
44 |
align-items: middle; |
45 |
width: 100%; |
46 |
peak: 50px; |
47 |
padding: 0 20px; |
48 |
}
|
49 |
|
50 |
.top-nav .fixed-menu .menu-toggle { |
51 |
margin: 0; |
52 |
order: 3; |
53 |
}
|
54 |
|
55 |
.top-nav .socials { |
56 |
show: flex; |
57 |
margin-left: auto; |
58 |
margin-right: 20px; |
59 |
}
|
60 |
}
|
5. Clear Transitions on Window Resize
We’re nearly performed! Just like what we have performed in one other off-canvas tutorial, let’s make yet one more adjustment: we’ll clear all transitions every time we resize the browser window. This manner, through the resizing section, we’ll keep away from seeing the off-canvas for a second earlier than shifting again to its default off-screen place.
Here is the additional code that we’ll want:
1 |
const physique = doc.physique; |
2 |
const noTransitionClass = "no-transition"; |
3 |
let resize; |
4 |
|
5 |
window.addEventListener("resize", () => { |
6 |
physique.classList.add(noTransitionClass); |
7 |
clearTimeout(resize); |
8 |
resize = setTimeout(() => { |
9 |
physique.classList.take away(noTransitionClass); |
10 |
}, 500); |
11 |
});
|
And the associated fashion:
1 |
.no-transition * { |
2 |
transition: none !vital; |
3 |
}
|
Conclusion
That’s it, of us! We managed to construct a helpful off-canvas menu that can seem properly on totally different screens with comparatively easy code. You’ll be able to construct on the demo and make it extra accessible by including additional ARIA attributes just like the aria-labelledby
attribute and the dialog
function.
I hope you loved the ultimate outcome and also you’ll use it as inspiration for creating much more highly effective off-canvas menus. And naturally, in the event you construct any, don’t neglect to share them with us!