How to Animate a Hamburger Menu Icon
How to animate a hamburger icon into a close button: the geometry, the timing, pairing it with the menu panel, and the accessibility attributes that must follow.
Core Takeaway
The hamburger icon is a state label: three lines mean closed, an X means open. Animate the top and bottom lines into the diagonal strokes by translating and rotating them, and fade or hide the middle line. Keep the transition short and symmetrical, and make sure the button's accessible name and aria-expanded change with the icon, not just the animation.
It is a state indicator, not decoration
Users read the icon to know whether the menu is open. The animation should make the state change obvious without becoming a performance. The most legible transformation is three lines becoming an X, because the shapes map onto each other and the eye can follow the movement.
The geometry that works
Position the top and bottom bars, translate them to the vertical centre, then rotate one by 45 degrees and the other by -45 degrees. The middle bar fades out or scales to zero. Because you are changing transform, the browser can animate it cheaply. Keep the bars the same length so the X is symmetrical.
Timing and symmetry
The two diagonals should arrive together. If one rotates before the other, the icon looks like it is falling apart. Short and even is better than slow and elaborate. Reversing the animation should return the exact original geometry so the closed state is pixel-identical to the start.
Pair it with the panel
The icon change and the menu opening are one event. If the panel slides in from the side, start the icon change at the same moment, not after the panel finishes. If the panel covers the icon, the animation is wasted; keep the close control visible or provide a clear close button inside.
Accessibility comes first
Use a real button with an accessible name that changes between open and close, and keep aria-expanded in sync. The icon itself is decorative, so hide it from assistive technology. When the menu opens, move focus into it or to the first item, trap focus if it behaves like a dialog, and return focus to the button when it closes.
Reduced motion
For reduced motion, swap the icon without rotating it, or use a very short cross-fade. The state change still needs to be clear, so do not remove the visual difference; just remove the travel.
Production Implementation Snippet
.icon span {
transition: transform 180ms ease, opacity 180ms ease;
}
.icon[data-open="true"] span:nth-child(1) {
transform: translateY(6px) rotate(45deg);
}
.icon[data-open="true"] span:nth-child(2) {
opacity: 0;
}
.icon[data-open="true"] span:nth-child(3) {
transform: translateY(-6px) rotate(-45deg);
}
@media (prefers-reduced-motion: reduce) {
.icon span { transition: opacity 80ms linear; }
}Key Principles to Remember
- The icon communicates open or closed, so keep it in sync with state
- Translate and rotate the outer bars, fade the middle one
- Both diagonals should land together
- Start the icon change with the panel, not after it
- Update aria-expanded and the accessible name with the icon
Frequently Asked Questions
Sources
- Disclosure Pattern — W3C WAI-ARIA Authoring Practices
- Dialog (Modal) Pattern — W3C WAI-ARIA Authoring Practices
- prefers-reduced-motion — MDN Web Docs