DEV Community

loading...
Cover image for Just CSS: CSS Only Hamburger Nav Animation

Just CSS: CSS Only Hamburger Nav Animation

uzomezu profile image Kevin Mezu ・3 min read

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>

Enter fullscreen mode Exit fullscreen mode

CSS:


* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background: blueviolet;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

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.

Trigram of Heaven

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);
}

Enter fullscreen mode Exit fullscreen mode

Doing this should give you the following:

hamburger-nav-image

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);
}
Enter fullscreen mode Exit fullscreen mode

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

Alt Text

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)

pic
Editor guide
Collapse
anitagraham profile image
Anita Graham

Is your HTML valid?
Can the input element handle a div 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

<input type="checkbox" class="menu_button">
<div class="menu_button_burger"></div>
Enter fullscreen mode Exit fullscreen mode

Otherwise a good tutorial and great idea

Collapse
uzomezu profile image
Kevin Mezu Author

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!

Collapse
jrbell989 profile image
Jason Bell • Edited

I think you're correct about this bit not being valid html:

<input type="checkbox" class="menu-btn">
  <div class="menu-btn-burger"></div>
</input>
Enter fullscreen mode Exit fullscreen mode

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.

Collapse
jordandchappell profile image
Jordan Chappell • Edited

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.

Collapse
uzomezu profile image
Kevin Mezu Author

Yes! I've added it now thank you for the heads up

Collapse
thereedybear profile image
Reed

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 and details.menu[open] > summary would switch it to the x. States/animations on [open] and :not([open]). But I'm not sure if this betrays proper html 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.

Collapse
alynva profile image
Alisson Nunes

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

Collapse
ikurosaki profile image
ikurosaki

Muy hermoso, gracias por tu aporte.