100% CSS Hamburger Menus

Let’s build a hamburger menu for a mobile device that requires 0 Javascript.

We’ll need some HTML:

<nav class="navigation">
<label for="main-nav">Menu
<input type="checkbox" id="main-nav">
<ul id="navigation">
<li><a href="/web-design/">Web Design</a></li>
<li><a href="/contact/">Say Hi!</a></li>

So what we’ve got here is a nav element, which is completely appropriate for a mobile navigation menu.

Within that, we have a label wrapping our input that’s a checkbox. So, when you click the label, since it does wrap the checkbox, clicking anywhere on the checkbox toggles our checkbox.

We’ll then use some fairly modern CSS fanciness to make that control the ul showing.

Here’s the CSS:

// pseudo-elements to create our hamburger menu
label[for='main-nav'] {
position: relative;
padding: 1rem;
z-index: var(--highest);
label[for='main-nav']:before, label[for='main-nav']:after {
left: 0;
transition:transform 250ms, top 250ms, color 250ms;
label[for='main-nav'], label[for='main-nav']:before, label[for='main-nav']:after {
display: block;
background: black;
border-radius: --var(tiny-radius);
font-size: 1rem;
padding: 0;
height: .1rem;
width: 2rem;
color: transparent !important;
label[for='main-nav']:before {top:-0.5rem;}
label[for='main-nav']:after {top:.5rem;}

// change the hamburger menu to an X once it's clicked
label[for='main-nav']:has(input#main-nav:checked) {background:transparent;}
label[for='main-nav']:has(input#main-nav:checked):before {
transform: rotate(45deg);
left: 0;
top: 0;
background: white;
label[for='main-nav']:has(input#main-nav:checked):after {
transform: rotate(-45deg);
top: 0;
left: 0;
background: white;

// hide our checkbox
input#main-nav {
display: none;

// style our actual navigation menu
.h ul {
background: black;
position: fixed;
top: 0;
right: 100vw;
bottom: 0;
left: -100vw;
z-index: var(--higher);
transition: right 250ms;
padding: 6rem 1rem 1rem 2rem;
.h ul a {
color: white;
text-decoration: none;
font-size: 1.25rem;
font-weight: 650;

// when the checkbox is clicked, show the navigation
// in this case, it slides out from off screen
label[for='main-nav']:has(input#main-nav:checked) + ul#navigation {
right: 0;
left: 0;

Unless years have gone by, you can see it in action on a smaller screen at Say Hi, Durango!

Up Next: Strip XML Version & Encoding from an SVG File with PHP