webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Unelte
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Formulare
  12. 12Date și backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animații
  16. 16Testare
  17. 17Arhitectură
Animații · Lecția 2 din 4

Motion pentru React

motion.div, initial/animate/exit, AnimatePresence, variants și stagger, layout, scroll, spring.

Actualizat

Ce este Motion

Motion (fostul Framer Motion) e librăria de animații cea mai folosită în React. Ideea: înlocuiești un tag HTML cu varianta lui motion. și descrii stările, nu pașii — Motion calculează animația dintre ele.

npm i motion
'use client'
import { motion } from 'motion/react'

export function Card() {
  return <motion.div initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3 }} />
}

Componentele motion.* sunt Client Components — fișierul are 'use client'. Poți păstra pagina ca Server Component și să animezi doar bucăți mici.

Proprietățile de bază

Prop Ce face
initial starea de pornire (la montare)
animate starea țintă — când se schimbă, Motion animă spre ea
exit starea la demontare (necesită AnimatePresence)
transition duration, ease, delay, sau type: 'spring' cu stiffness / damping / bounce
whileHover, whileTap, whileFocus stări temporare la interacțiune
whileInView stare când elementul intră în ecran (+ viewport={{ once: true }})
layout animă automat schimbările de mărime / poziție din layout
layoutId două elemente diferite cu același id se „transformă” unul în altul

Ieșiri: AnimatePresence

React scoate imediat un element din DOM când nu mai e randat — nu e timp de animație. AnimatePresence îl ține până se termină exit:

<AnimatePresence>
  {open && (
    <motion.div key="panel" initial={{ opacity: 0, y: -8 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -8 }} />
  )}
</AnimatePresence>

Variants și stagger

Variants = stări cu nume, definite o dată și propagate copiilor. Ideal pentru liste:

import { motion, stagger } from 'motion/react'

const list = { hidden: {}, show: { transition: { delayChildren: stagger(0.06) } } }
const item = { hidden: { opacity: 0, y: 16 }, show: { opacity: 1, y: 0 } }

<motion.ul variants={list} initial="hidden" whileInView="show" viewport={{ once: true }}>
  {products.map(p => <motion.li key={p.id} variants={item}>{p.name}</motion.li>)}
</motion.ul>

Copiii nu au nevoie de initial / animate — moștenesc numele stărilor de la părinte.

Layout animations — efectul „wow” cu o linie

<motion.div layout className={expanded ? 'w-full' : 'w-40'} />     // mărimea se animă automat
{tabs.map(tab => (
  <button key={tab} onClick={() => setActive(tab)} className="relative px-3 py-1">
    {active === tab && <motion.span layoutId="tab-indicator" className="absolute inset-0 rounded-md bg-hover" />}
    <span className="relative">{tab}</span>
  </button>
))}

Indicatorul „alunecă” de la un tab la altul — fără niciun calcul de poziție.

Scroll

const { scrollYProgress } = useScroll()                      // 0 → 1 pe toată pagina
const scaleX = useSpring(scrollYProgress)                     // netezit cu spring
<motion.div style={{ scaleX }} className="fixed inset-x-0 top-0 h-1 origin-left bg-accent" />   // bară de progres

const y = useTransform(scrollYProgress, [0, 1], [0, -200])   // parallax

useTransform = interpolare: mapează un interval de intrare pe unul de ieșire.

Spring vs tween

Tween (duration + ease) Spring
Durată fixă rezultă din fizică
Senzație controlată, precisă naturală, „vie”
Întrerupere la mijloc poate sări continuă lin, păstrează viteza
Când opacitate, culoare, fade-uri mișcare, mărime, drag, gesturi

Pe scurt

  • motion.div + initial / animate / exit; AnimatePresence pentru ieșiri.
  • Variants + stagger() pentru liste; whileInView pentru apariții la scroll.
  • layout / layoutId pentru tranziții de layout; useScroll + useTransform pentru scroll; spring pentru mișcare.

Surse oficiale

Exerciții

Ți-a fost utilă pagina?

Un click — fără cont.