A CSS hamburger menu hides the main navigation links behind a three-bar button on narrow screens. A media query shows the button below a chosen width, CSS draws the icon and the panel, and the open or closed state sits on a button element. It works on phones and on any desktop window that gets too narrow for the links to fit on one line.

Before the animation, there’s the label. WebAIM’s 2025 analysis of 1,000,000 home pages found empty buttons, meaning buttons with no accessible name, on 29.6% of them. A bare three-bar icon with no text or aria-label falls into that group.

What is a CSS hamburger menu?

See the Pen
The ultimate hamburger menu
by Charles (@CharlesSmart)
on CodePen.

Charles Smart created what many developers consider the ultimate mobile-friendly navigation. The beauty lies in its simplicity and cross-browser compatibility.

Most people mean the three-line icon in a phone header that opens the site’s links. Built with HTML and CSS, with or without JavaScript, it collapses the main navigation on small screens and brings it back when tapped.

Every version has an icon drawn with CSS or SVG, a toggle control that flips the open and closed state, a navigation panel holding the links, and a breakpoint rule that sets the screen width where the icon replaces the inline links.

Below that width, the menu swaps a visible row of links in the site navigation for a single button. Above it, the links return and the icon disappears.

You’ll also hear it called a menu icon, nav toggle, mobile menu, off-canvas menu or navigation drawer. The name usually follows how the panel opens, not how the icon looks.

It is not a mega menu and not a tab bar. The hamburger is only the trigger. A dropdown can sit behind it, or a slide-in drawer, and sometimes a full-screen overlay.

For the wider interface pattern, see this explainer on the hamburger menu in UI design.

How to draw the hamburger icon and animate it into an X

One empty span and its two pseudo-elements are enough for the icon. To get the X, rotate the outer bars 45 degrees and hide the middle one. It all runs on CSS transform and transition, so the only script involved is the toggle itself.

Building the three bars

See the Pen
Single Element Animated Hamburger Menu CSS Only
by Josh Fabean (@fabean)
on CodePen.

Josh Fabean’s single-element approach proves that effective UI doesn’t need complex markup. The entire menu icon uses just one HTML element.

There are several ways to draw the icon, and they trade markup size against animation freedom.

  • The span with ::before and ::after is where I’d start. The span is the middle bar and the pseudo-elements are the top and bottom bars, so there’s no extra markup and each bar moves on its own.
  • A single element with aspect-ratio and a linear-gradient background can paint all 3 bars. It’s the lightest markup, but the bars share one box, so they cannot rotate separately.
  • Inline SVG, with lines or paths, stays sharp at any size. It also takes the most markup.
  • The trigram character U+2630 works as button text and needs no CSS at all. The glyph depends on the font, though, and it can never become an X.

Inline SVG is the right pick when the icon has to match an existing icon set. A guide to placing SVG in HTML covers the embedding options.

<button class="menu-toggle" type="button" aria-expanded="false" aria-label="Menu">
<span class="bars"></span>
</button>
.menu-toggle { --bar-w: 24px; --bar-h: 2px; --bar-gap: 7px; }

.bars,
.bars::before,
.bars::after {
display: block;
width: var(--bar-w);
height: var(--bar-h);
border-radius: 2px;
background: currentColor;
transition: transform 250ms ease, top 250ms ease, background-color 250ms ease;
}
.bars { position: relative; }
.bars::before,
.bars::after { content: ""; position: absolute; left: 0; }
.bars::before { top: calc(var(--bar-gap) * -1); }
.bars::after  { top: var(--bar-gap); }

A 7px offset on a 2px bar leaves a 5px gap between bars. Keeping size and gap in custom properties means one edit resizes the whole icon.

Turning the bars into an X

See the Pen
Morphing Hamburger Menu with CSS
by lmgonzalves (@lmgonzalves)
on CodePen.

The morphing menu by lmgonzalves demonstrates how shape transitions can clearly communicate state changes in navigation.

Here is the open state.

.menu-toggle[aria-expanded="true"] .bars { background: transparent; }
.menu-toggle[aria-expanded="true"] .bars::before { top: 0; transform: rotate(45deg); }
.menu-toggle[aria-expanded="true"] .bars::after  { top: 0; transform: rotate(-45deg); }

The middle bar goes transparent while both outer bars slide to the center line and cross. Because the styling hangs off aria-expanded, the icon and the announced state stay in step. One attribute drives both.

For timing, 200ms to 300ms is enough. Past 400ms the icon starts to lag behind the tap.

The change is a small micro-interaction, and its job is to confirm the tap registered before the panel finishes opening.

The gradient-only icon is the one that can’t morph this way. Swap its background for a second gradient that draws a close icon and you get a swap instead of an animation.

Choosing a toggle mechanism for the CSS hamburger menu

See the Pen
Cool hamburger toggle effect
by Kriszta (@vajkri)
on CodePen.

Kriszta’s toggle effect demonstrates how subtle animation details can make interactions feel more satisfying. The clean transformation provides clear user feedback.

For a production site I’d use a button with a few lines of JavaScript. The popover attribute is the native alternative when the audience runs current browsers, and the checkbox hack suits prototypes only.

MechanismNeeds JavaScriptOpen state for screen readersSupport status
Checkbox hackNoAnnounced as a checkboxAll modern browsers
Button with JavaScriptYes, a short scriptaria-expanded set by the scriptAll modern browsers
details and summaryNoNative, with screen reader gapsBaseline widely available
Popover attributeNoImplicit aria-expanded on the buttonBaseline newly available

The checkbox hack uses a hidden checkbox, a label styled as the icon and the :checked state with a sibling combinator to show and hide the list. No script is needed.

In a keyboard test run by ThePlusAddons (Chromium at 390px, September 2026), Space opened the menu. Enter did nothing, and Escape did not close it.

The checkbox has to come before the list and share its parent, because the general sibling combinator only looks forward. Screen readers announce a checkbox, not a menu control, and since nothing in CSS can update aria-expanded, the open state is never reported.

With a real button, a click flips aria-expanded and the list’s hidden state. Enter and Space work because the browser treats them as clicks on a button.

W3C’s WAI-ARIA Authoring Practices builds its disclosure navigation example the same way, with aria-controls and aria-expanded on a button.

That example skips the ARIA menu role on purpose, because the role demands composite-widget focus handling that ordinary site navigation does not need.

GOV.UK Frontend v4.3.0 moved the header’s mobile menu to the hidden attribute, and the Menu button starts hidden so visitors whose script fails to load never see a dead control.

One failure mode to watch. If you hide the list in CSS and rely on script to open it, a failed script leaves visitors with no links at all. The build in the next section avoids that by letting the script do the hiding.

The native details and summary widget opens and closes without script. Baseline, the cross-browser availability label from the web-features project, lists it as widely available since July 2022.

Cloud Four tested it as a burger menu. VoiceOver on iOS with Safari did not announce the summary’s role, and Dragon Naturally Speaking could not activate it by voice.

Commenters on that post counter that the gaps are general assistive technology support for details, not something specific to menus. The cause differs, but the result for the visitor does not.

The popover attribute works differently again. A button with popovertarget opens any element marked popover, with no script. MDN documents several behaviors that matter for a menu. In the default auto mode, Escape and a click outside both close it (light dismiss). The button gets an implicit aria-expanded and aria-details link to the popover, the popover lands in a logical spot in the keyboard focus order when it opens, and top layer rendering means parent position and overflow rules cannot clip it.

Browser support has a dated catch. web.dev announced the Popover API as Baseline in April 2024, then corrected itself. The feature entered Baseline on January 27, 2025, because light dismiss failed on some mobile browsers.

MDN pages carry both labels in different versions, so check the current Baseline badge before relying on either date.

My rule of thumb is to pick the popover attribute when every browser in your analytics is current. Otherwise use the button, which works everywhere and costs a short script.

How to build a responsive CSS hamburger menu step by step

See the Pen
Mobile Menu Animation
by Stas Melnikov (@melnik909)
on CodePen.

Stas Melnikov’s bottom-centered approach challenges conventional navigation UI placement. By positioning the menu button at the screen bottom, it improves touchscreen accessibility for one-handed use.

Build the narrow layout first, let a short script collapse the list, then add one media query that restores the inline links on wide screens.

  1. Write the markup: a header with a nav landmark, a button that starts hidden, and the list of links.
  2. Style the narrow layout as the default, with no media query.
  3. Let the script reveal the button and collapse the list, so visitors without JavaScript keep every link.
  4. Toggle aria-expanded and the list’s hidden state when the button is clicked.
  5. Add a media query that hides the button and lays the links out in a row above the breakpoint.
  6. Style the open panel, then resize the window and test with the keyboard.
<header class="site-header">
<a class="logo" href="/">Brand</a>
<nav aria-label="Main">
<button class="menu-toggle" type="button" aria-expanded="false"
aria-controls="site-menu" aria-label="Menu" hidden>
<span class="bars"></span>
</button>
<ul id="site-menu" class="site-menu">
<li><a href="/products/">Products</a></li>
<li><a href="/pricing/">Pricing</a></li>
<li><a href="/contact/">Contact</a></li>
</ul>
</nav>
</header>
.site-menu { list-style: none; margin: 0; padding: 0; }

@media (min-width: 48em) {
.menu-toggle { display: none; }
.site-menu { display: flex; gap: 1.5rem; }
}
const toggle = document.querySelector('.menu-toggle');
const menu = document.getElementById('site-menu');

toggle.hidden = false;
menu.hidden = true;

toggle.addEventListener('click', () => {
const open = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute('aria-expanded', String(!open));
menu.hidden = open;
});

A media query decides when the toggle gives way to the inline links. The author rule display: flex beats the browser’s display: none for the hidden attribute, so the list reappears above the breakpoint even though the script set hidden.

Writing the narrow layout as the default and adding wide rules with min-width is mobile-first design. The desktop-first alternative uses max-width and works, but every narrow-screen rule has to undo a desktop one.

This script covers click, Enter and Space. Escape handling and focus return belong with the accessibility rules, so add them before shipping.

Choosing the breakpoint

em equals 768px at the default 16px font size, which is the usual starting point. The right value is the width where your links stop fitting on one line.

The DWP Design System header, adapted from GOV.UK, collapses its links into a Menu button on viewports 768px wide or less. Without JavaScript the full navigation stays visible and the links wrap onto new lines.

To find your own number, drag the window from wide to narrow and note the width where the last link drops to a second row. Set the breakpoint just above that, so no band of widths shows a wrapped header. Retest after adding a link or translating labels, since longer labels move the breakpoint.

A header with seven links and a search field often runs out of room well before 768px. A fixed 768px leaves a broken tablet band whenever the links wrap at 900px.

Dropdown, off-canvas or full-screen overlay panels

A dropdown suits a short list. Long lists, or ones with submenus, belong in an off-canvas panel, and a full-screen overlay only makes sense when the toggle is the main way around the site. All of them sit above page content, and the larger two should also stop the page scrolling underneath.

For layering, give the header position: relative and a z-index above the content, and keep the panel inside the header so it inherits that layer.

One class on the root element handles the scroll lock. Swap the click handler from the build for a shared function, and unlock when the viewport crosses the breakpoint.

const root = document.documentElement;
const wide = matchMedia('(min-width: 48em)');

function setOpen(open) {
toggle.setAttribute('aria-expanded', String(open));
menu.hidden = !open;
root.classList.toggle('menu-open', open);
}

toggle.addEventListener('click', () => {
setOpen(toggle.getAttribute('aria-expanded') !== 'true');
});

wide.addEventListener('change', (e) => {
if (e.matches) setOpen(false);
});
.menu-open { overflow: hidden; }

Without the change listener, resizing past the breakpoint with the panel open leaves the page locked.

Dropdown

The panel drops from the header edge and covers part of the page. It needs the least CSS of the lot.

Position it absolute, with top at 100% of the header and left and right at 0. Let content set the height, and add max-height with overflow-y: auto for long lists. Closing happens on a second tap of the toggle, a tap on a link, or Escape.

The mechanism is the one behind other CSS dropdown menus, with a button as the trigger instead of hover.

The page stays scrollable behind a short panel, so the scroll lock is optional here.

Off-canvas panel

This sidebar menu represents pure efficiency in responsive design. Using only HTML and CSS, it creates a slide-out menu that works across different viewport settings.

Sliding a panel in from a hidden state works in CSS alone since August 2024, when @starting-style and transition-behavior: allow-discrete became Baseline newly available (web.dev, August 8, 2024).

The build hides the list with the hidden attribute, which means display: none, so nothing can transition. Add display to the transition list with allow-discrete, and give the entry state inside @starting-style.

@media (max-width: 47.99em) {
.site-menu {
position: fixed;
inset: 0 auto 0 0;
width: min(20rem, 85vw);
background: #fff;
transition: transform 300ms ease, display 300ms allow-discrete;
}
.site-menu[hidden] { transform: translateX(-100%); }

@starting-style {
.site-menu { transform: translateX(-100%); }
}
}

This is the drawer pattern from UI design, and the panel width stays capped so a strip of the page remains visible.

A panel parked off-screen with transform alone stays in the tab order, and keyboard users tab into links they cannot see. The hidden attribute avoids that, because display: none removes the links from the tab order.

Full-screen overlay

See the Pen
100% CSS Hamburger Animation
by Álvaro (@alvarotrigo)
on CodePen.

Álvaro’s full-screen takeover creates an immersive navigation experience that transforms the entire viewport when activated.

A full-screen overlay is a fixed panel with no gaps around it.

.site-menu {
position: fixed;
inset: 0;
overflow-y: auto;
background: #fff;
}

Prefer inset: 0. If you need an explicit height, use 100dvh, because MDN documents vh as equal to the large viewport, with browser toolbars retracted, so 100vh runs past the visible screen while a toolbar shows.

A plain fixed panel serves one list of links for both layouts, but the focus handling is yours to write. A modal dialog opened with showModal() gets the top layer, an inert page, Escape to close and initial focus from the browser (MDN), but a closed dialog cannot double as the inline link row on wide screens.

Accessibility requirements for a CSS hamburger menu

Start with a real button that has one constant name, then keep aria-expanded and aria-controls in sync with the panel. Escape should close it and return focus to the button. Add a visible focus ring, a target of at least 24 by 24 CSS pixels, and reduced motion handling.

Keyboard and screen reader behavior

A native button gives you Enter and Space with no extra code. Give it one constant label, such as “Menu”. The aria-expanded value flips with the panel, and aria-controls points at the list’s id. Escape closes the panel and sends focus back to the toggle, as keyboard users expect from modal dialogs (MDN). The focus ring is a :focus-visible outline, and it stays.

Both attributes come from ARIA, and W3C’s APG disclosure navigation example sets aria-expanded to false for a hidden container and to true for a visible one.

document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && toggle.getAttribute('aria-expanded') === 'true') {
setOpen(false);
toggle.focus();
}
});
.menu-toggle:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}

Sources split on the label. A widely shared uxdesign.cc guide says to switch aria-label from “Open menu” to “Close menu”, while W3C’s APG button pattern says a toggle’s label must not change when its state changes.

The APG rule is written for aria-pressed toggles, and the same logic holds for aria-expanded: a changing label plus a changing state announces the same thing twice. Keep one label.

Target size

CriterionLevelMinimum target
WCAG 2.2 SC 2.5.8, Target Size (Minimum)AA24 by 24 CSS pixels
WCAG SC 2.5.5, Target Size (Enhanced)AAA44 by 44 CSS pixels

W3C’s Understanding document for 2.5.8 lets a smaller target pass when a 24px circle centered on it touches no other target.

The icon is 24px wide with 2px bars, so the button is the target, not the icon. Pad the button to 44 by 44 and it passes both criteria.

.menu-toggle {
min-width: 44px;
min-height: 44px;
}

Links inside the open panel count as targets too. Give each row enough padding to reach the same height.

Reduced motion

Turn the transitions off for people who ask for less motion.

@media (prefers-reduced-motion: reduce) {
.bars,
.bars::before,
.bars::after,
.site-menu { transition: none; }
}

MDN describes the prefers-reduced-motion media feature as detecting a device setting that minimizes non-essential motion, available across browsers since January 2020. Place the block after the transition rules, so it wins on source order.

The state change stays visible: the X appears and the panel opens instantly.

Why a CSS hamburger menu stops working

Most breakage traces back to script timing, stacking contexts, transformed ancestors, stale open state or rule order.

SymptomCauseFix
Toggle does nothingScript runs before the button existsAdd defer, or load the script last
Panel appears behind contentHeader sits in a lower stacking contextRaise the z-index of the context holding the header
Fixed panel stays inside the headerAn ancestor has transform or filterRemove it, or move the panel out
Menu stays open after a link tapOn-page links do not reload the pageClose the menu on link click
Toggle shows on wide screensA later display rule overrides the media queryMove the media query below the base rules

Stacking contexts trip people up first. A z-index only competes inside its own stacking context. MDN lists position: fixed, position: sticky, a transform other than none and some will-change values among the properties that start a new one.

So a header with z-index: 1000 still loses when it sits inside a context that ranks below the hero section’s context.

Transformed ancestors cause a quieter version of the same grief. MDN’s containing block documentation says an absolutely or fixed positioned element can take its containing block from the nearest ancestor with a transform or filter.

A header that hides on scroll by animating transform: translateY() becomes that ancestor, and a fixed panel inside it pins to the header box instead of the screen.

Stale open state comes from same-page links. They change the scroll position without a reload, so nothing resets the menu. One listener fixes it:

menu.addEventListener('click', (e) => {
if (e.target.closest('a')) setOpen(false);
});

Rule order is the last one. Media queries add no specificity, so a base .menu-toggle rule with a display value that comes after the query wins and shows the icon on wide screens.

When should you skip the hamburger menu?

Skip it on desktop widths, and on phones whenever the site has four or five top-level links. That is Nielsen Norman Group’s guidance, built on a study with 179 participants across 6 live sites on desktop and smartphones (Pernice and Budiu, June 26 and July 24, 2016).

The figures from that study point the same way.

  • Navigation use was 27% with hidden navigation versus 48% visible on desktop, and 57% hidden versus 86% combo on mobile.
  • Content discoverability fell by more than 20% with hidden navigation.
  • Tasks took at least 39% longer on desktop and 15% longer on mobile.

The data dates from 2016. NN/G expected only familiarity with the icon to improve over time, and called low salience, low information scent and extra work permanent costs.

NN/G’s two 2016 articles also differ on the phone threshold: the June piece says 4 or fewer top-level links should stay visible, the July follow-up says 4 to 5.

My short version is this. On wide screens, show the links. On phones with up to five links, show them too, after checking they fit at the narrowest width you support. With more links than that, use combo navigation, a few visible links plus the toggle, which beat fully hidden navigation in the figures above.

When the toggle stays, NN/G’s mobile guidelines ask for a larger footprint, a label, a clear separation from the logo and, where possible, sticky navigation so the control stays reachable.

Its mobile comparison shows why. SupermarketHQ’s large Browse button drew significantly more navigation use than Bloomberg’s small unlabeled arrow beside the logo, which many participants missed altogether.

NN/G’s closing advice is a usability test on your own visitors, because guidelines depend on context.

A hamburger menu fits a phone layout with more than five top-level links and nothing else competing for the header.

CSS Hamburger Menu Examples

The Showy Menu with a Color Blast by Brandon Ward

See the Pen
Full width menu & SVG animation
by Brandon Ward (@brandondward)
on CodePen.

Brandon’s approach combines full-screen navigation with vibrant color transitions that grab attention. What makes this example valuable is how it handles the menu transformation while maintaining strong visual hierarchy.

Slide it Right with Praveen Bisht

See the Pen
Slide Out Navigation Menu
by Praveen Bisht (@prvnbist)
on CodePen.

Praveen’s slide-out navigation menu demonstrates excellent touch interface optimization. The subtle animation provides clear user feedback without feeling overwhelming.

Playful Menu Moves Over Here

See the Pen
Hamburger Menu Animations
by Tamino Martinius (@Zaku)
on CodePen.

Tamino Martinius showcases four distinct menu animations in one interface. Each transformation provides a different visual cue about the navigation state.

The Animated Show by Nicholas M. Smith

See the Pen
Animated Burger/Menu Icon
by Nicholas M. Smith (@icutpeople)
on CodePen.

Nicholas created a refined burger icon animation that communicates state changes clearly. The smooth transition from menu to close icon provides excellent user experience.

Dive into the CSS Deep End

See the Pen
CSS Challenge – Day 2
by Elitsa Dimitrova (@elitsa_dimitrova)
on CodePen.

Elitsa Dimitrova’s CSS challenge pushes the boundaries of what’s possible with pure CSS preprocessors. The complex animations showcase advanced front-end development techniques.

The Artistic Touch by Arjan Jassal

See the Pen
Material Design Menu
by Arjan Jassal (@arjancodes)
on CodePen.

Arjan’s Material Design approach showcases how to implement established design systems within a hamburger menu context. The animations follow Google’s motion principles closely.

Twist and Shout with this Navigation

This unique approach rotates the entire page content to reveal the navigation. While unconventional, it creates a memorable interaction pattern that users remember.

Sil van Diepen’s Attention Grabber

See the Pen
Menu test – css only – effects
by Sil van Diepen (@silvandiepen)
on CodePen.

Sil’s implementation focuses on making the menu icon impossible to miss through clever effects. The animation draws attention at exactly the right moment.

Keep It Classic and Centred

See the Pen
Navbar
by Álvaro (@alvarotrigo)
on CodePen.

This example by Álvaro takes a traditional approach to the menu component but executes it flawlessly. The centered navigation maintains cross-device experience consistency.

The 3D Magic Trick

See the Pen
3D Hamburger Transformicon
by Bennett Feely (@bennettfeely)
on CodePen.

Bennett Feely’s 3D transformation creates depth and dimension in what would otherwise be a flat interface element. The menu transformation feels physical and tangible.

From Burger to Book

See the Pen
Hamburger Menu to Book Menu
by Halil İbrahim Nuroğlu (@haibnu)
on CodePen.

Halil İbrahim Nuroğlu created an unexpected transformation from hamburger to book icon. This creative approach connects the menu concept to content in a clever way.

Adding Some Dimension

This implementation adds perspective to create a 3D effect that makes the menu feel like a physical object. The combination of CSS and JavaScript creates a sophisticated interaction.

Two-toned Delight

See the Pen
Hamburger Menu (CSS only)
by Youri Pailloux (@Zorlimar)
on CodePen.

Youri Pailloux’s half-white, half-blue design creates visual interest through color division. The expanding animation transforms the small icon into a full header section.

Purple Rain, Purple Icon

See the Pen
Hamburger Open Animation
by Sarath AR (@sarath-ar)
on CodePen.

Sarath AR uses a bold purple backdrop to make the menu icon stand out. The color creates immediate visual hierarchy in the navigation UI.

Bounce it with Jack

See the Pen
Jumping Hamburger Menu Icon
by Jack Thomson (@Jackthomsonn)
on CodePen.

Jack Thomson adds playfulness with a bouncing animation. The slight elasticity makes the interface feel more responsive and alive.

Open Sesame! Or…Close?

See the Pen
Hamburger menu open/close animation
by Jonathan Suh (@jonsuh)
on CodePen.

Jonathan Suh’s open/close animation provides crystal-clear state indication. The transformation leaves no doubt about whether the menu is open or closed.

Keep it Slick and Pro

See the Pen
CSS(SASS) Hamburger Menu Animation
by Derek Morash (@derekmorash)
on CodePen.

Derek Morash’s SASS-based animation creates a professional, refined interaction. The subtle movements convey quality and attention to detail.

Stretch and Conquer

See the Pen
Simple animated navigation menu
by Oury (@ourystd)
on CodePen.

Oury’s navigation stretches the toggle into a horizontal bar, creating a satisfying expansion effect that reveals menu items progressively.

Sketch it Out, Dude!

See the Pen
Drawn Hamburger Transition
by Jesse Couch (@designcouch)
on CodePen.

Jesse Couch’s drawn effect creates the impression of the hamburger being sketched and erased in real-time. This artistic approach adds character to the interface.

Elastic Fantastic

See the Pen
hamburger menu elastic
by Davide Cantelli (@cant89)
on CodePen.

Davide Cantelli’s elastic menu creates a stretching effect that feels physical and satisfying. The animation mimics real-world materials.

Burger Party by Mikael

See the Pen
Flippin’ burgers
by Mikael Ainalem (@ainalem)
on CodePen.

Mikael Ainalem’s collection of eight different hamburger animations demonstrates the variety possible within this UI pattern. Each animation has distinct personality and behavior.

Atomic Boom Boom!

See the Pen
Atomic Hamburger Menu CSS
by Alex Coven (@alcoven)
on CodePen.

Alex Coven’s atomic hamburger menu uses a particle effect to transform the icon, creating a memorable and distinctive interaction.

Go Circular or Go Home

See the Pen
CSS Gooey Menu (Version 4)
by Lucas Bebber (@lbebber)
on CodePen.

Click and BOOM! A circle bursts into a bunch of mini-circles, each with its own secret.

Groove with the Moves

See the Pen
hamburger menu css animation
by jun xu (@junxu)
on CodePen.

Animation so smooth, it’ll have you swaying side to side. Feel the rhythm with every click!

Slide and Ride

See the Pen
Adaptive menu on CSS only
by Álvaro (@alvarotrigo)
on CodePen.

Slide into the web scene with this snazzy sliding menu. All flash without the dash of heavy code.

Double Trouble: CSS & jQuery

See the Pen
Hamburger Menu – CSS and jQuery
by rv7 (@Rahul_V7)
on CodePen.

Mix a dash of CSS with a sprinkle of jQuery, and voila! A banging burger menu, complete with a header bar.

Highlight the Night

See the Pen
Click highlighter on menu button using :after
by Rhys Matthew (@rhyspacker)
on CodePen.

Kudos to Rhys Matthew for this gem. Click and get that cool highlight effect, all Google Material Design-esque.

Triple Threat

See the Pen
Hamburger animation & Triple background color using CSS
by Himalaya Singh (@himalayasingh)
on CodePen.

From a burger to an X with a whole mood switch for the background. Talk about drama!

Wild Child Burger

See the Pen
Obnoxious Burger
by Adam Kuhn (@cobra_winfrey)
on CodePen.

Adam Kuhn brings the wild side with this burger. Click and get ready for some chaos!

One More for the Road

See the Pen
Another Hamburger 🍔 Animation | CSS
by Joshua Ward (@joshuaward)
on CodePen.

If you’re still hungry for more, check out this piece. It’s another burger with all the right moves.

CSS hamburger menu FAQ

Who designed the hamburger icon?

Norm Cox designed it for the Xerox Star, introduced in 1981, as a container for contextual menu choices. By Cox’s own account, he kept the three bars as simple as a road sign and made them mimic the menu list they opened.

Can I make a hamburger menu with Tailwind CSS?

Yes, using responsive prefixes instead of a hand-written media query. Tailwind’s breakpoints are mobile-first and based on min-width, with md starting at 768px, so md:hidden on the button and hidden md:flex on the list swap the toggle for the inline links.

A short script still has to flip aria-expanded.

Which Bootstrap classes build a hamburger menu?

The .navbar-toggler class goes on the button, .navbar-collapse on the list container, and a .navbar-expand-* class, from sm to xxl, sets the breakpoint.

The toggler keeps a constant “Toggle navigation” label, carries aria-expanded and aria-controls, and needs Bootstrap’s JavaScript to open.

How do I add a submenu inside a hamburger menu?

Keep the parent item as a link, add a sibling disclosure button with aria-expanded and aria-controls, and nest the submenu list inside the same list item. W3C’s APG disclosure navigation example with top-level links uses that structure.

Each parent needs its own tap target, because touch screens have no hover.

Testing a CSS hamburger menu before launch

Run the keyboard-only walkthrough before any audit. Automated checks cover only part of the problem, and the order below puts the manual one first for that reason.

  1. Walk through it by keyboard with Tab, Space, Enter and Escape, and confirm focus returns to the toggle.
  2. Run the Lighthouse accessibility audit in Chrome DevTools.
  3. Do a pass on a physical phone.

Lighthouse states that automatic detection finds only a subset of accessibility issues, so a green score leaves Escape handling and focus return unverified. Chrome’s documentation calls DevTools device mode a first-order approximation that never simulates some mobile behaviors, which makes a physical phone the last gate.

Repeat the sequence whenever the toggle mechanism changes, for example when a checkbox hack gives way to a button, because the two expose state differently (position verified October 12, 2026).

A web accessibility checklist covers the rest of the page once the toggle passes.

Bogdan Sandu
Latest posts by Bogdan Sandu (see all)