AccueilServicesPortfolioArticles
Contact
Créer un Header Responsive avec Menu Burger en Framer Motion

Créer un Header Responsive avec Menu Burger en Framer Motion

TutorielsReactFramer

Dans ce tutoriel, je vais vous apprendre à créer un header responsive avec un menu burger animé en utilisant Framer Motion et React. Ce composant va se comporter de manière fluide et s’adapter à différentes tailles d’écran.

Préparer le projet

Tout d'abord, vous devez avoir un projet React avec Framer Motion installé. Si ce n'est pas encore fait, vous pouvez l'ajouter avec cette commande :

npm install framer-motion

En plus de Framer Motion, j'utilise Lucide Icons pour l'icône du menu burger. Si vous ne l'avez pas encore installé, voici la commande pour l'ajouter à votre projet :

npm install lucide-react

Cela vous permettra d'utiliser l'icône de menu burger dans votre composant.

Créer le composant Header

Nous allons créer un composant Header avec un logo et un menu qui se transforme en menu burger lorsque l'écran devient petit.

"use client";
import { useState, useRef } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Menu } from "lucide-react";
import Link from "next/link";

// Éléments de la navigation
const navItems = [
  { text: "Accueil", href: "/" },
  { text: "À propos", href: "/about" },
  { text: "Services", href: "/services" },
  { text: "Contact", href: "/contact" },
];

export default function Header() {
  const [isOpen, setIsOpen] = useState(false);
  const menuRef = useRef(null);

  // Fonction pour ouvrir ou fermer le menu
  const toggleMenu = () => {
    setIsOpen(!isOpen);
  };

  // Variants pour l'overlay
  const overlayVariants = {
    hidden: { opacity: 0 },
    visible: { opacity: 0.2 },
  };

  // Variants pour l'animation du conteneur (staggerChildren appliqué ici)
  const navVariants = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: {
        staggerChildren: 0.2,
        duration: 0.6,
        ease: "easeInOut",
      },
    },
  };

  // Variants pour chaque élément de la liste
  const itemVariants = {
    hidden: { opacity: 0, y: 20 },
    visible: { opacity: 1, y: 0 },
  };

  return (
    <header className="fixed left-0 top-0 z-50 flex w-full items-center justify-between bg-white px-6 py-2 shadow-md md:py-4">
      {/* Logo à gauche */}
      <Link href="/" className="text-2xl font-bold text-cyan-900">
        Logo
      </Link>

      {/* Liens visibles uniquement sur écrans larges */}
      <nav className="hidden items-center space-x-8 md:flex">
        {navItems.map((item) => (
          <Link
            key={item.text}
            href={item.href}
            className="text-lg font-normal text-cyan-900 hover:text-cyan-600"
          >
            {item.text}
          </Link>
        ))}
      </nav>

      {/* Bouton burger visible uniquement sur petits écrans */}
      <button
        onClick={toggleMenu}
        aria-label="Ouvrir le menu"
        className="flex flex-col items-center justify-center space-y-2 p-3 focus:outline-none xl:hidden"
      >
        <Menu size={32} color="black" />
      </button>

      {/* Overlay pour fermer le menu au clic */}
      <AnimatePresence>
        {isOpen && (
          <motion.div
            className="fixed inset-0 z-40 bg-black"
            initial="hidden"
            animate="visible"
            exit="hidden"
            variants={overlayVariants}
            transition={{ duration: 0.4 }}
            onClick={() => setIsOpen(false)}
          />
        )}
      </AnimatePresence>

      {/* Menu latéral avec animation */}
      <motion.nav
        ref={menuRef}
        initial={{ x: "100%", opacity: 0, scaleX: 0.6, rotateY: 90 }}
        animate={{
          x: isOpen ? "0%" : "100%",
          opacity: isOpen ? 1 : 0,
          scaleX: isOpen ? 1 : 0.6,
          rotateY: isOpen ? 0 : 90,
        }}
        transition={{
          duration: 0.6,
          ease: "easeInOut",
        }}
        className="fixed right-0 top-0 z-50 flex h-full w-72 items-center justify-center bg-cyan-900 p-5 text-white shadow-lg sm:hidden"
        aria-hidden={!isOpen}
        role="navigation"
      >
        <motion.ul
          variants={navVariants}
          initial="hidden"
          animate={isOpen ? "visible" : "hidden"}
          className="flex flex-col items-center space-y-12"
        >
          {navItems.map((item) => (
            <motion.li key={item.text} variants={itemVariants}>
              <Link href={item.href} className="text-2xl font-normal">
                {item.text}
              </Link>
            </motion.li>
          ))}
        </motion.ul>
      </motion.nav>
    </header>
  );
}
  • Logo : À gauche, nous avons un simple lien avec le texte "Logo" pour simuler un logo.
  • Menu sur grands écrans : Les liens de navigation sont visibles par défaut sur les écrans larges grâce à la classe hidden sm:flex.
  • Bouton burger : Sur les petits écrans, le bouton burger (menu) devient visible avec la classe sm:hidden. Lorsque l'on clique dessus, il ouvre un menu latéral animé.
  • Animation du menu burger : Le menu se slide depuis la droite avec une transition fluide, en utilisant Framer Motion pour gérer l'animation.
Alexis Pennel

Alexis Pennel

Publié le 10 décembre 2024

Retour aux articles

Autres posts qui pourraient vous plaire

  • Composant de cartes avec skeleton loader en React.js et Tailwind CSS

    Composant de cartes avec skeleton loader en React.js et Tailwind CSS

  • Créer une animation de liste UL avec Framer Motion sur React et Next.js

    Créer une animation de liste UL avec Framer Motion sur React et Next.js

  • Barre de recherche avec React et Framer Motion

    Barre de recherche avec React et Framer Motion

  • Créez des Animations Fluides avec Framer Motion en React

    Créez des Animations Fluides avec Framer Motion en React

Un projet en tête ? Obtenez un devis gratuit.

Posez-moi vos questions ou décrivez votre projet web pour recevoir un devis gratuit, sans engagement, sous 48 heures.

Photo de Alexis Pennel, développeur web freelance
Alexis Pennel
Bonjour, moi, c'est Alexis ! Vous avez des questions sur mes services ou un projet en tête ? Décrivez-le en quelques mots pour recevoir un devis gratuit, poser vos questions, ou réserver un entretien !

Ou contactez-moi directement par email ou WhatsApp.