Blog / CSS

Animated CSS Menus: The Complete Guide

Master the art of animated navigation menus: transformable hamburger, slide-in menu, fluid dropdown, tabs with sliding indicator and mega menu. Modern CSS techniques with minimal JavaScript.

Introduction to animated menus

Navigation is the cornerstone of user experience on a website. A well-designed and animated menu does more than just function: it guides the user, provides clear visual feedback, and reinforces your interface's identity.

In this complete guide, we'll explore 7 types of animated menus you can implement with modern CSS and minimal JavaScript. Each technique comes with an interactive demo and the complete code.

💡
CSS-first approach

All animations in this guide use CSS for transitions and transformations. JavaScript only steps in to toggle classes, ensuring optimal performance.

1. Animated hamburger menu (transform to X)

The hamburger icon has become a standard for mobile menus. The animation that transforms the three bars into a cross (X) clearly signals to the user that the menu is open and can be closed.

Animation principle

The animation relies on three simultaneous transformations:

  • Top bar: 45-degree rotation + translation downward
  • Middle bar: disappears (opacity or scale)
  • Bottom bar: -45-degree rotation + translation upward
Click to animate
hamburger.css
.hamburger {
  width: 48px;
  height: 48px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 12px;
}

.hamburger span {
  display: block;
  width: 24px;
  height: 2px;
  background: white;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  transform-origin: center;
}

/* Active state - transform to X */
.hamburger.active span:nth-child(1) {
  transform: rotate(45deg) translate(5px, 6px);
}

.hamburger.active span:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}

.hamburger.active span:nth-child(3) {
  transform: rotate(-45deg) translate(5px, -6px);
}

2. Slide-in menu (drawer)

The drawer menu slides in from the side of the screen, often accompanied by a dark overlay. This is the standard pattern for mobile menus that contain many options.

Click the button
Home
Services
Portfolio
Contact
slide-menu.css
.slide-menu {
  position: fixed;
  top: 0;
  left: 0;
  width: 280px;
  height: 100vh;
  background: #12121a;
  transform: translateX(-100%);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 1001;
}

.slide-menu.active {
  transform: translateX(0);
}

/* Dark overlay */
.slide-menu-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  visibility: hidden;
  transition: all 0.3s;
  z-index: 1000;
}

.menu-open .slide-menu-overlay {
  opacity: 1;
  visibility: visible;
}

Dropdown menus are essential for organizing hierarchical navigation. A smooth animation with fade + slide conveys quality and guides the user's eye.

Click to open
dropdown.css
.dropdown {
  position: relative;
}

.dropdown-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 220px;
  background: #12121a;
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 12px;
  padding: 8px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.3);

  /* Initial hidden state */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px) scale(0.95);
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.dropdown.active .dropdown-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

/* Arrow animation */
.dropdown-trigger svg {
  transition: transform 0.3s;
}

.dropdown.active .dropdown-trigger svg {
  transform: rotate(180deg);
}

4. Animated tabs with sliding indicator

Tabs with an indicator that slides between them provide excellent visual feedback. The user clearly sees the active tab and the transition is smooth and satisfying.

Click on the tabs
tabs.css
.tabs {
  display: flex;
  position: relative;
  background: #0a0a0f;
  padding: 4px;
  border-radius: 12px;
}

.tab {
  padding: 12px 24px;
  background: transparent;
  border: none;
  color: #a1a1aa;
  cursor: pointer;
  z-index: 1;
  transition: color 0.3s;
}

.tab.active {
  color: white;
}

/* Indicateur glissant */
.tab-indicator {
  position: absolute;
  height: calc(100% - 8px);
  top: 4px;
  background: #6366f1;
  border-radius: 8px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 0;
}
tabs.js
const tabs = document.querySelectorAll('.tab');
const indicator = document.querySelector('.tab-indicator');

function moveIndicator(tab) {
  indicator.style.width = tab.offsetWidth + 'px';
  indicator.style.left = tab.offsetLeft + 'px';
}

tabs.forEach(tab => {
  tab.addEventListener('click', () => {
    tabs.forEach(t => t.classList.remove('active'));
    tab.classList.add('active');
    moveIndicator(tab);
  });
});

// Position initiale
moveIndicator(document.querySelector('.tab.active'));

5. Mega menu with reveal

Mega menus are perfect for content-rich sites. The reveal animation creates a sense of depth and allows many options to be displayed in an organized manner.

mega-menu.css
.mega-menu-content {
  position: absolute;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  background: #12121a;
  border-radius: 16px;
  padding: 24px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.3);

  /* Animation reveal */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.mega-menu.active .mega-menu-content {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.mega-menu-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

6. Animated underline on hover

The animated underline effect is an elegant classic for navigation links. The line draws from left to right on hover, creating a subtle yet effective effect.

Hover over the links
nav-underline.css
.nav-link {
  position: relative;
  padding: 12px 0;
  color: #a1a1aa;
  transition: color 0.3s;
}

.nav-link::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 0;
  height: 2px;
  background: linear-gradient(90deg, #6366f1, #8b5cf6);
  transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.nav-link:hover {
  color: white;
}

.nav-link:hover::after,
.nav-link.active::after {
  width: 100%;
}
🎨
Variant: animation from the center

For an underline that appears from the center, use left: 50% and transform: translateX(-50%) in addition to animating the width.

7. Menu accessibility

A beautiful menu is not enough: it must be accessible to all users, including those who navigate by keyboard or with a screen reader.

Essential ARIA attributes

  • aria-expanded: indicates whether a menu is open or closed
  • aria-haspopup: signals that an element triggers a menu
  • aria-controls: links the button to the menu it controls
  • role="menu" and role="menuitem": define the structure
accessible-dropdown.html
<div class="dropdown">
  <button
    class="dropdown-trigger"
    aria-expanded="false"
    aria-haspopup="true"
    aria-controls="dropdown-menu"
  >
    Menu
  </button>

  <ul
    id="dropdown-menu"
    role="menu"
    aria-label="Main menu"
  >
    <li role="menuitem">Option 1</li>
    <li role="menuitem">Option 2</li>
  </ul>
</div>

Keyboard navigation

An accessible menu must support:

  • Enter / Space: open/close the menu
  • Escape: close the menu
  • Up/down arrows: navigate between items
  • Tab: exit the menu
keyboard-navigation.js
dropdown.addEventListener('keydown', (e) => {
  const items = dropdown.querySelectorAll('[role="menuitem"]');
  const currentIndex = Array.from(items).indexOf(document.activeElement);

  switch(e.key) {
    case 'Escape':
      closeDropdown();
      trigger.focus();
      break;

    case 'ArrowDown':
      e.preventDefault();
      const nextIndex = (currentIndex + 1) % items.length;
      items[nextIndex].focus();
      break;

    case 'ArrowUp':
      e.preventDefault();
      const prevIndex = currentIndex <= 0 ? items.length - 1 : currentIndex - 1;
      items[prevIndex].focus();
      break;
  }
});
⚠️
Reduced motion

Respect user preferences with @media (prefers-reduced-motion: reduce) to disable or reduce animations for people sensitive to motion.

Conclusion

Animated menus are much more than an aesthetic detail: they guide the user, provide visual feedback, and reinforce your interface identity. By mastering the techniques presented in this guide, you can create smooth and professional navigation.

Key takeaways:

  • Use transform and opacity for performant animations
  • The cubic-bezier(0.4, 0, 0.2, 1) function produces natural transitions
  • Combine visibility with opacity for clean transitions
  • Never forget accessibility (ARIA, keyboard navigation)
  • Test on mobile and respect prefers-reduced-motion
🚀
Go further

Find ready-to-use navigation components in our effects library, with copyable and customizable code.