Guide Complet Framer Motion pour React
Découvrez comment créer des animations web fluides et performantes avec Framer Motion. De l'installation aux techniques avancées, ce guide vous donnera toutes les clés pour maîtriser cette bibliothèque d'animation incontournable.
📋 Table des matières
🚀 Introduction à Framer Motion
Framer Motion est une bibliothèque d'animation pour React qui simplifie la création d'animations fluides et performantes. Développée par l'équipe Framer, elle offre une API intuitive qui permet de créer des interfaces utilisateur dynamiques sans sacrifier les performances.
Pourquoi choisir Framer Motion ?
- API déclarative : Définissez vos animations directement dans le JSX
- Performances optimisées : Utilise le GPU pour des animations fluides
- Gestes tactiles : Support natif du drag & drop et des gestes
- AnimatePresence : Gérez facilement les animations d'entrée/sortie
- Écosystème React : Intégration parfaite avec les hooks et le state
💡 Le saviez-vous ?
Framer Motion est utilisé par des entreprises comme Stripe, Coinbase, et bien sûr Framer. Sa popularité vient de sa capacité à créer des animations complexes avec un code minimal.
📦 Installation et configuration
Installation via npm ou yarn
# Avec npm
npm install framer-motion
# Avec yarn
yarn add framer-motion
# Avec pnpm
pnpm add framer-motion
Configuration avec Next.js
Si vous utilisez Next.js (comme nous le recommandons chez Atypik Code), vous pouvez utiliser Framer Motion directement sans configuration supplémentaire.
// components/AnimatedComponent.jsx
"use client" // Important pour Next.js 13+
import { motion } from 'framer-motion'
export default function AnimatedComponent() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
Hello Framer Motion !
</motion.div>
)
}
🎨 Animations de base avec motion
Le composant motion
Tous les éléments HTML peuvent être animés en les préfixant avec motion.
:
import { motion } from 'framer-motion'
// Div animée
<motion.div />
// Bouton animé
<motion.button />
// Image animée
<motion.img />
// SVG animé
<motion.svg />
Propriétés fondamentales
- initial : État initial de l'animation
- animate : État final de l'animation
- transition : Configuration de la transition
- exit : Animation de sortie (avec AnimatePresence)
Exemple : Bouton avec hover
function AnimatedButton() {
return (
<motion.button
className="px-6 py-3 bg-purple-600 text-white rounded-lg"
whileHover={{
scale: 1.05,
boxShadow: "0 10px 25px rgba(139, 92, 246, 0.3)"
}}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 300 }}
>
Cliquez-moi !
</motion.button>
)
}
🎭 AnimatePresence : gérer les animations d'entrée/sortie
AnimatePresence
permet d'animer les composants qui apparaissent et disparaissent du DOM. C'est essentiel pour les modales, les notifications, ou tout contenu conditionnel.
Exemple : Modal animée
import { motion, AnimatePresence } from 'framer-motion'
import { useState } from 'react'
function AnimatedModal() {
const [isOpen, setIsOpen] = useState(false)
return (
<>
<button onClick={() => setIsOpen(true)}>
Ouvrir la modal
</button>
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/50 flex items-center justify-center"
onClick={() => setIsOpen(false)}
>
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.8, opacity: 0 }}
transition={{ type: "spring", damping: 20 }}
className="bg-white p-8 rounded-xl"
onClick={(e) => e.stopPropagation()}
>
<h2>Modal animée</h2>
<p>Contenu de la modal avec Framer Motion</p>
<button onClick={() => setIsOpen(false)}>
Fermer
</button>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</>
)
}
⚠️ Point important
AnimatePresence
doit envelopper les éléments conditionnels, pas l'élément animé lui-même. Les enfants directs doivent avoir une prop key
unique.
🎯 Hooks avancés et contrôle d'animations
useAnimation() : Contrôle programmatique
import { motion, useAnimation } from 'framer-motion'
import { useEffect } from 'react'
function ControlledAnimation() {
const controls = useAnimation()
useEffect(() => {
// Séquence d'animations
const sequence = async () => {
await controls.start({ x: 100 })
await controls.start({ y: 100 })
await controls.start({ x: 0, y: 0 })
}
sequence()
}, [controls])
return (
<motion.div
animate={controls}
className="w-20 h-20 bg-purple-500 rounded-lg"
/>
)
}
useInView() : Animations au scroll
import { motion, useInView } from 'framer-motion'
import { useRef } from 'react'
function ScrollAnimation() {
const ref = useRef(null)
const isInView = useInView(ref, { once: true })
return (
<motion.div
ref={ref}
initial={{ opacity: 0, y: 50 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
transition={{ duration: 0.8 }}
className="p-8 bg-gray-800 rounded-xl"
>
<h3>Animation au scroll</h3>
<p>Ce contenu s'anime quand il devient visible</p>
</motion.div>
)
}
🎨 Animations de path SVG
Une des fonctionnalités les plus impressionnantes de Framer Motion est la capacité d'animer les chemins SVG avec pathLength
.
function AnimatedSVG() {
return (
<svg width="200" height="200" viewBox="0 0 200 200">
<motion.circle
cx="100"
cy="100"
r="80"
stroke="#8B5CF6"
strokeWidth="4"
fill="transparent"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 2, ease: "easeInOut" }}
/>
</svg>
)
}
Exemple avancé : Logo animé
function AnimatedLogo() {
const draw = {
hidden: { pathLength: 0, opacity: 0 },
visible: (i) => {
const delay = 1 + i * 0.5
return {
pathLength: 1,
opacity: 1,
transition: {
pathLength: { delay, type: "spring", duration: 1.5, bounce: 0 },
opacity: { delay, duration: 0.01 }
}
}
}
}
return (
<motion.svg
width="200"
height="200"
viewBox="0 0 200 200"
initial="hidden"
animate="visible"
>
<motion.path
d="M 50 100 L 150 100"
stroke="#8B5CF6"
strokeWidth="4"
variants={draw}
custom={0}
/>
<motion.path
d="M 100 50 L 100 150"
stroke="#8B5CF6"
strokeWidth="4"
variants={draw}
custom={1}
/>
</motion.svg>
)
}
⚡ Optimisation des performances
Propriétés GPU-accélérées
Pour des performances optimales, privilégiez ces propriétés :
x, y
au lieu deleft, top
scale
au lieu dewidth, height
rotate
au lieu de transformations CSSopacity
pour les fondus
Layout animations avec layoutId
function SharedLayoutAnimation() {
const [isExpanded, setIsExpanded] = useState(false)
return (
<motion.div
layout
layoutId="expandable-card"
className={isExpanded ? "large-card" : "small-card"}
onClick={() => setIsExpanded(!isExpanded)}
>
<motion.h2 layout="position">Titre</motion.h2>
{isExpanded && (
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Contenu additionnel
</motion.p>
)}
</motion.div>
)
}
🚀 Astuce performance
Utilisez will-change: transform
en CSS pour préparer le GPU, et transform3d(0,0,0)
pour forcer l'accélération matérielle sur les anciens navigateurs.
💼 Cas d'usage concrets
1. Menu hamburger animé
function AnimatedHamburger({ isOpen, toggle }) {
const topVariants = {
closed: { rotate: 0, y: 0 },
open: { rotate: 45, y: 8 }
}
const centerVariants = {
closed: { opacity: 1 },
open: { opacity: 0 }
}
const bottomVariants = {
closed: { rotate: 0, y: 0 },
open: { rotate: -45, y: -8 }
}
return (
<button onClick={toggle} className="flex flex-col w-8 h-8 justify-center">
<motion.span
className="w-8 h-1 bg-white mb-1"
variants={topVariants}
animate={isOpen ? "open" : "closed"}
/>
<motion.span
className="w-8 h-1 bg-white mb-1"
variants={centerVariants}
animate={isOpen ? "open" : "closed"}
/>
<motion.span
className="w-8 h-1 bg-white"
variants={bottomVariants}
animate={isOpen ? "open" : "closed"}
/>
</button>
)
}
2. Carrousel d'images fluide
function ImageCarousel({ images }) {
const [current, setCurrent] = useState(0)
return (
<div className="relative overflow-hidden w-full h-96">
<AnimatePresence mode="wait">
<motion.img
key={current}
src={images[current]}
initial={{ x: 300, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: -300, opacity: 0 }}
transition={{ type: "spring", damping: 20 }}
className="absolute inset-0 w-full h-full object-cover"
/>
</AnimatePresence>
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2">
{images.map((_, index) => (
<button
key={index}
onClick={() => setCurrent(index)}
className={`w-3 h-3 mx-1 rounded-full ${
current === index ? 'bg-white' : 'bg-white/50'
}`}
/>
))}
</div>
</div>
)
}
✅ Meilleures pratiques
1. Gérez l'accessibilité
// Respectez les préférences utilisateur
const prefersReducedMotion = useReducedMotion()
<motion.div
animate={{
x: prefersReducedMotion ? 0 : 100
}}
transition={{
duration: prefersReducedMotion ? 0 : 0.5
}}
/>
2. Utilisez des variants pour la réutilisabilité
const fadeInUp = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6 }
}
}
// Réutilisable sur plusieurs composants
<motion.div variants={fadeInUp} initial="hidden" animate="visible">
Contenu animé
</motion.div>
3. Optimisez les re-renders
- Utilisez
useMemo
pour les objets de transition complexes - Évitez les animations inline dans le render
- Préférez les variants aux objets inline
- Utilisez
layout
avec parcimonie
🎨 Notre approche chez Atypik Code
Nous intégrons Framer Motion dans tous nos projets Next.js pour créer des expériences utilisateur mémorables. L'animation n'est pas juste décorative, elle guide l'utilisateur et améliore l'UX.
🎓 Conclusion
Framer Motion est un outil puissant qui transforme la façon dont nous créons des interfaces React. Avec une API intuitive et des performances optimisées, il permet de créer des animations de qualité professionnelle sans complexité excessive.
Les points clés à retenir :
- Commencez simple avec les props
initial
,animate
ettransition
- Utilisez
AnimatePresence
pour les animations d'entrée/sortie - Exploitez les hooks comme
useInView
etuseAnimation
pour des cas avancés - Optimisez les performances avec les propriétés GPU-accélérées
- Respectez l'accessibilité avec
useReducedMotion
Chez Atypik Code, nous utilisons Framer Motion pour tous nos projets web en Haute-Savoie, créant des expériences utilisateur modernes et engageantes.
Besoin d'un site avec des animations professionnelles ?
Nous créons des sites web modernes avec Framer Motion pour les entreprises en Haute-Savoie. Animations fluides, performances optimisées et design sur mesure.