There are different ways to create an animated hamburger menu icon. For example, you can only use CSS or an SVG icon along with some JavaScript.
In this tutorial, we'll cover another method. That said, we'll grab such an icon from LottieFiles library and learn how to embed it into a responsive page header by taking advantage of Lottie Player.
Sound challenging?
Without further intro, let’s check out what we’ll be building:
See the Pen Practicing Lottie Player: How to Embed an Animated Hamburger Menu Into a Web Page by George (@georgemarts) on CodePen.
Notice the hamburger and menu animations that happen each time you click on the hamburger icon.
Additionally, be sure to check the demo on a wide screen (>900px) to see how the menu layout changes.
For this demonstration, we're going to use a hamburger icon created by Michael Foster.
The animated hamburger menu that we'll include into our page
This icon consists of 90 frames. The first 45 frames animate the icon up to its open state, while the last 45 ones animate it up to its close one. Keep an eye on these numbers as we'll use them later on.
Coming up next, we’ll include the required Lottie Player JavaScript file in our project:
The required Lottie Player JavaScript file
Our page will consist of a header. Inside it, we'll place the following items:
Here's the associated markup:
<header class="page-header">
<nav>
<div class="page-header-inner">
<a href="" class="toggle-menu" role="button" aria-controls="menu-wrapper" aria-label="Open navigation" aria-expanded="false">
<lottie-player src="https://assets8.lottiefiles.com/packages/lf20_nzuitqg1.json"></lottie-player>
</a>
<a href="" class="logo">Bikes4U</a>
</div>
<div id="menu-wrapper" class="menu-wrapper">
<ul>
<li>
<a href="">...</a>
</li>
...
</ul>
</div>
</nav>
</header>
Pay attention to the following:
lottie-player
custom element and set its src
property to the corresponding JSON file.role="button"
. Normally, we would wrap it around a button
element. However, as lottie-player
emits div
s, it's semantically incorrect to put a div
inside a button
.aria-label
, aria-expanded
, and aria-controls
ARIA attributes. As we'll discuss later, the values of the first two attributes will change depending on the menu state.As a next step, we'll define some reset styles. Nothing important.
So, to make the page a little more attractive, we'll add a custom Google Font to the project.
Also, we’ll define the no-transition
class that will help us disable transitions on window resize. More on that in a bit.
Here are our reset styles:
:root {
--white: white;
--orange: #ffb128;
--lightorange: #ffdf86;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
a {
text-decoration: none;
color: inherit;
}
body {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 100vh;
font: 500 20px/1.2 "Montserrat", sans-serif;
background: linear-gradient(to bottom, var(--orange), var(--lightorange));
}
.no-transition {
transition: none !important;
}
On screens wider than 900px, the header layout will look like this:
The header layout on wide screens
On narrow screens, the header layout will change to this:
The header layout on narrow screens
Some key things to note:
Here are all the header styles:
/*CUSTOM VARIABLES HERE*/
.page-header {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding: 40px 20px 0;
}
.page-header nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1200px;
margin: 0 auto;
}
.page-header .page-header-inner {
display: flex;
align-items: center;
}
.page-header .page-header-inner * {
z-index: 1;
}
.page-header .toggle-menu {
margin-right: 10px;
width: 70px;
}
.page-header lottie-player {
display: flex;
}
.page-header .logo {
font-weight: bold;
font-size: 30px;
}
.page-header .menu-wrapper {
transform: translateY(-200px);
transition: transform 1s ease-in-out;
}
.page-header .menu-wrapper ul {
display: flex;
align-items: center;
}
.page-header .menu-wrapper li:not(:last-child) {
margin-right: 35px;
}
.page-header .menu-wrapper a {
display: inline-block;
padding: 5px;
}
@media (max-width: 900px) {
.page-header {
padding-top: 20px;
}
.page-header .menu-wrapper {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
transform: translateY(-100vh);
overflow-y: auto;
background: var(--orange);
}
.page-header .menu-wrapper ul {
padding: 100px 0;
margin: auto;
flex-direction: column;
}
.page-header .menu-wrapper li:not(:last-child) {
margin: 0 0 20px;
}
}
Each time we click on the menu link, the following actions will happen:
menu-open
class of the header. This will determine whether the menu will appear or not.menu-open
class, the hamburger icon should be animated up to its open state. To achieve this, we have to play frames between 0 and 45.menu-open
class, the hamburger icon should be animated back to its close state. To achieve this, we have two options. Either play frames between 46 and 90 or play frames between 45 and 0 (reverse the animation).aria-label
and aria-expanded
ARIA attributes.At this point, let me go through one tricky thing. As you might already know, Lottie Player is a wrapper of Lottie-web library. This library provides the playSegments()
method that allows us to play specific frames. So, to get access to this method and be able to use it via the web player, we have first to call its getLottie()
method.
With all the aforementioned in mind, here's the JavaScript code that implements this functionality:
const pageHeader = document.querySelector(".page-header");
const toggleMenu = document.querySelector(".toggle-menu");
const player = document.querySelector("lottie-player");
const menuWrapper = document.querySelector(".menu-wrapper");
const menuOpenedClass = "menu-open";
toggleMenu.addEventListener("click", function (e) {
e.preventDefault();
pageHeader.classList.toggle(menuOpenedClass);
if (pageHeader.classList.contains(menuOpenedClass)) {
this.setAttribute("aria-label", "Close navigation");
this.setAttribute("aria-expanded", "true");
player.getLottie().playSegments([0, 45], true);
} else {
this.setAttribute("aria-label", "Open navigation");
this.setAttribute("aria-expanded", "false");
player.getLottie().playSegments([45, 0], true);
//player.getLottie().playSegments([46, 90], true);
}
});
And the transition-related styles:
.page-header .menu-wrapper {
transition: transform 1s ease-in-out;
}
.page-header.menu-open .menu-wrapper {
transform: none;
}
Our header is almost ready! There's one small optional, yet nice-to-have enhancement that we can do. That said, we'll stop the menu transitions on window resize. That's where the earlier defined no-transition
class is needed.
Without going into more details, here's the JavaScript that handles this functionality:
...
const noTransitionClass = "no-transition";
let timer;
window.addEventListener("resize", function () {
menuWrapper.classList.add(noTransitionClass);
clearTimeout(timer);
timer = setTimeout(function () {
menuWrapper.classList.remove(noTransitionClass);
}, 500);
});
If you want to understand what it does, just remove the code above and resize the window when the menu is hidden. You'll notice that the mobile menu instantly appears before hiding.
That's all, folks! Thanks to Lottie Player, we managed to incorporate an animated hamburger menu as a part of a fully responsive page header. Hopefully, this exercise helped you understand just one of the endless capabilities of Lottie animations and why they are becoming increasingly popular these days.
Let's remind ourselves what we built during this tutorial:
See the Pen Practicing Lottie Player: How to Embed an Animated Hamburger Menu Into a Web Page by George (@georgemarts) on CodePen.
Go ahead, fork this demo and customize it in line with your expectations! Even better, enhance a web page with the techniques you learned today and show us the result!
Thanks for reading!