Adding animation can be a quick way to ensure your user knows where to look and what to do when they interact with your application. Plus it just looks really cool, and we like cool points!
Here is a simple Hamburger Animation using CSS Selectors and the Checkbox attribute.
Steps
1. Boilerplate Setup
Start by setting up your generic CSS and HTML templates. I like to see my HTML like JavaScript or a React App, so we are going to isolate the hamburger icon like a component, style it, and then test it so we can reuse it in other applications.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hamburger Animation</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<input type="checkbox" class="menu-btn">
<div class="menu-btn-burger"></div>
</input>
</body>
</html>
CSS:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: blueviolet;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
2. The Menu Button and CSS Trigram of Heaven
We are going to do something different from the norm, and actually use an input field as our parent element. Doing this helps us replace our JavaScript and simply leverage CSS selectors.
Start by Writing a class for the Menu Button called .menu-btn as such:
Menu Button
.menu-btn {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 80px;
height: 80px;
cursor: pointer;
transition: all 0.5s;
opacity: 0;
z-index: 2;
}
We want to create a check box that sits over top of our other elements. This way we can click the box like a button and activate its on and off state.
Trigram of Heaven
Fun fact: Trigram comes from the computational term n-gram, a series of contiguous items, or items that share a common border. A great example is word levels, for example:
the quick red
quick red fox
red fox jumps
fox jumps over
jumps over the
over the lazy
the lazy brown
lazy brown dog
This writing of "the quick brown fox jumps over the lazy dog" shows symmetry when written this way.
We are going to create our own Trigram with CSS to communicate visually the presence of a menu within our application.
Trigram Bars
Using ::before and ::after pseudo-elements, we will create the appearance of a trigram within our application.
.menu-btn-burger {
z-index: 0;
width: 50px;
height: 6px;
position: absolute;
background: white;
/* border-radius: 5px; */
transition: all 0.5s;
box-shadow: 0 2px 5px rgba(255, 101, 80, 0.5);
}
.menu-btn-burger::before,
.menu-btn-burger::after {
content: "";
position: absolute;
z-index: 0;
width: 50px;
height: 6px;
background: white;
/* border-radius: 5px; */
transition: all 0.5s ease-in-out;
box-shadow: 0 2px 5px rgba(255, 101, 80, 0.5);
}
/* Bottom Bar */
.menu-btn-burger::before {
transform: translateY(-16px);
}
/* Top Bar */
.menu-btn-burger::after {
transform: translateY(16px);
}
Doing this should give you the following:
Now its time to add animation for closed and open state.
3. Animation
CSS Selectors
CSS selectors apply styling to child components based on state of parent component. Since our menu button is a checkbox we can leverage the checked of unchecked state for animation purposes.
We need two state:
- Closed === Trigram of Heavan ☰
- Open === X symbol (No middle Bar) ✕
Since our menu will naturally begin in closed state, that means our animations need to match the Open State ( ✕ ) of the Trigram.
/* Animation */
/* Disappearing Middle Bar */
.menu-btn:checked + .menu-btn-burger {
transform: translateX(-50px);
background: transparent;
box-shadow: none;
}
/* Rotation to X symbol */
.menu-btn:checked + .menu-btn-burger::before {
transform: rotate(45deg) translate(35px, -35px);
}
.menu-btn:checked + .menu-btn-burger::after {
transform: rotate(-45deg) translate(35px, 35px);
}
We will tilt our top and bottom bars whilst removing the middle bar, to give the illusion of an X symbol. This kind of visual communication preserves our HTML elements, and creates a minimalist experience that is easier to code, and entertaining to use.
Final Product
Thanks For Reading! Wanna turn this into a full Hamburger Nav? Read My Article on : React.js Hamburger Nav Integration
Resources:
Kumar, P., Kumar, P., 27, V., 30, V., 2, H., 20, H., . . . 3, C. (2017, October 21). An Introduction to N-grams: What Are They and Why Do We Need Them? Retrieved December 14, 2020, from https://blog.xrds.acm.org/2017/10/introduction-n-grams-need/
Discussion (8)
Is your HTML valid?
Can the
input
element handle adiv
inside it?Input is a self closing element, so there is no
</input>
.I was trying to implement your very nice hamburger, but the html is always transformed to
Otherwise a good tutorial and great idea
Great Question! This is normal, CSS Selector properties still apply as long as the child element, directly follows the parent element. In this case as long as
.menu-btn-burger
is below the<input class="menu-btn"/>
the browser will run the code as expected.In most cases a code editor like VS-Code will validate your HTML for you after each commit/save. Especially in react.js apps, HTML is always run through a validator. Thanks for noticing this!
I think you're correct about this bit not being valid html:
The browser is basically "fixing" the markup and interpreting the
<div>
as a sibling adjacent to the<input>
rather than as a child of it. Otherwise the css wouldn't be working (the+
adjacent sib combinator would not be selecting the child<div>
).I ran into something similar a couple days ago when I had some invalid html, and the browser "fixed" it. But in my case, the css did not work, and it took me half an hour to spot my mistake!
Anyway, this is a really nice animation, and I love that it uses a checkbox (as it inherently maintains state). This is very easy to translate to any web app.
This is awesome! Really well written article with a great example of the stuff that is achievable in CSS.
I noticed that you have missed the
.menu-btn-burger
style in your provided CSS snippet, I'm assuming it should be placed in the list of class selectors above the::before
and::after
pseudo selectors.Yes! I've added it now thank you for the heads up
This is nice. I think I'd probably opt for a
<details><summary></summary>MENU CONTENT</details>
or something, where the<summary>
would be a hamburger menu anddetails.menu[open] > summary
would switch it to the x. States/animations on[open]
and:not([open])
. But I'm not sure if this betrays properhtml
semantics. I think as long as the menu itself (links & such) is still in a<nav>
we'd be all good. And I suppose details/summary could introduce some additional problems. Idk.Nice example! I just think that using differents timing function in the transitions, make the animation a little strange. Take a look using the same timing function: codepen.io/Alynva/pen/KKgWjNz
Muy hermoso, gracias por tu aporte.