Animacje komponent贸w z Framer Motion 馃殌

Animacje komponent贸w z Framer Motion 馃殌

01/04/2023
6 min read
Dzisiaj chcia艂bym przedstawi膰 Wam moje ulubione narz臋dzie do animacji w projektach React - Framer Motion! Jest to bardzo prosta i przyjemna do pracy biblioteka do pracy z animacjami
We wpisie tym przyjrzymy si臋 bli偶ej Framer Motion, om贸wimy jego najwa偶niejsze funkcje i nauczymy si臋, jak doda膰 piorunuj膮ce efekty do naszych aplikacji. Aby pokaza膰 Wam, jak to wszystko dzia艂a, zbudujemy razem prosty, ale efektowny komponent Drawer, kt贸ry doskonale sprawdzi si臋 w wielu projektach.
A przede wszystkim - przekonamy si臋, 偶e tworzenie animacji w React mo偶e by膰 naprawd臋 proste i przyjemne. Do dzie艂a! 馃帀

Animacje, interakcje i wi臋cej: Poznaj Framer Motion

Framer Motion oferuje szeroki zakres mo偶liwo艣ci, kt贸re pozwalaj膮 na tworzenie r贸偶norodnych animacji i interakcji w aplikacjach React. Oto niekt贸re z nich:
  1. Animacje CSS: Umo偶liwia animowanie r贸偶nych w艂a艣ciwo艣ci CSS, takich jak kolor, wielko艣膰, marginesy czy pozycj臋 element贸w.
  2. Drag and drop: Prosta implementacja mechanizmu "przeci膮gnij i upu艣膰" dla element贸w na stronie.
  3. Gesty: Obs艂uga gest贸w, takich jak przesuni臋cia czy przybli偶ania, co pozwala na tworzenie bardziej interaktywnych aplikacji.
  4. Spring physics: Zastosowanie fizyki spr臋偶ynowej do animacji, co pozwala na tworzenie bardziej realistycznych i p艂ynnych efekt贸w.
  5. Orchestration: Kontrolowanie kolejno艣ci i synchronizacji animacji wielu element贸w, dzi臋ki czemu mo偶emy tworzy膰 z艂o偶one sceny.
  6. Variants: Tworzenie zdefiniowanych wariant贸w animacji dla r贸偶nych stan贸w, co u艂atwia zarz膮dzanie i kontrolowanie animacji.
  7. Shared layout animations: U艂atwienie animacji mi臋dzy r贸偶nymi komponentami, np. podczas zmiany stron w aplikacji.
  8. AnimatePresence: 艁atwe dodawanie animacji wej艣cia i wyj艣cia dla komponent贸w, kt贸re pojawiaj膮 si臋 i znikaj膮 z drzewa DOM.
  9. Server-side rendering (SSR) compatibility: Wsp贸艂praca z renderowaniem po stronie serwera, co u艂atwia tworzenie zoptymalizowanych aplikacji.
  10. Performance optimizations: Optymalizacja wydajno艣ci animacji, dzi臋ki czemu dzia艂aj膮 one p艂ynnie nawet na s艂abszych urz膮dzeniach.
Dzi臋ki tym funkcjom Framer Motion pozwala na tworzenie atrakcyjnych, p艂ynnych i responsywnych animacji w aplikacjach React. W kolejnych cz臋艣ciach tego wpisu zastosujemy niekt贸re z tych mo偶liwo艣ci, aby stworzy膰 drawer komponent z animacjami i gestami.

Konfiguracja projektu

Instalujemy bibliotek臋 standardowo za pomoc膮 npm/yarn:
npm install framer-motion
Nast臋pnie tworzymy nowy komponent i piszemy struktur臋 HTML:
function Drawer() {
const [open, setOpen] = useState(false);
return (
<>
{open && (
<div
className="drawerOverlay"
/>
)}
<div
className='drawer'
>
<div
className='drawerInner'
>
<DrawerHeader />
<DrawerContent />
</div>
</div>
</>
);
}
I stylizujemy troch臋 za pomoc膮 CSS:
.drawer {
font-family: 'Open Sans', sans-serif;
position: fixed;
top: calc(100% - 94px);
width: 100%;
left: 0;
right: 0;
height: 90%;
z-index: 4;
pointer-events: initial;
}
.drawerInner {
height: 100%;
}
.drawerOverlay {
width: 100%;
height: 100vh;
position: fixed;
background-color: rgba(0, 0, 0, 0.3);
top: 0;
left: 0;
z-index: 3;
backdrop-filter: blur(0.4rem);
pointer-events: initial;
transition: all 0.3s ease-in-out;
}
Maj膮c tak przygotowan膮 podstawow膮 struktur臋, mo偶emy przyst膮pi膰 do animowania otwierania i zamykania drawera oraz obs艂ugi gestu drag.

Dodanie animacji z framer motion

Zajmijmy si臋 najpierw animacj膮 overlaya. Za艂o偶enie jest takie, 偶e kiedy nasz komponent b臋dzie otwarty, w tle poka偶emy p贸艂prze藕roczysty wyblurowany overlay. B臋dzie on r贸wnie偶 obs艂ugiwa艂 zamkni臋cie drawera po klikni臋ciu na overlay. Element ten renderuje si臋 dopiero, kiedy zmienna open b臋dzie ustawiona na true i tak samo usuwa si臋 z DOM kiedy zamkniemy drawer. Jako 偶e zamkni臋cie overlaya sprawia, 偶e element znika z DOM, musimy zastosowa膰 tutaj <AnimatePresence>.
Jest to komponent dostarczany przez framer motion, kt贸ry pozwala animowa膰 elementy, kt贸re znikaj膮 z DOM. Nie daliby艣my rady tego zrobi膰 za pomoc膮 zwyk艂ego CSS-a.
Overlayowi dodamy r贸wnie偶 drobn膮 animacj臋 opacity. Aby to zrobi膰, musimy przygotowa膰 obiekt, kt贸ry b臋dzie zawiera艂 konfiguracje animacji. W framer motion mo偶emy to zrobi膰 za pomoc膮 Variants:
const overlayVariants: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1 },
};
Obiekt reprezentuje 2 stany, jakie przyjmie nasz overlay - opacity: 0 i opacity: 1. Dzi臋ki temu uzyskamy efekt p艂ynnego pojawiania si臋 i znikania, zamiast skokowego.
<AnimatePresence>
{open && (
<motion.div
className="drawerOverlay"
initial="hidden"
animate="visible"
exit="hidden"
onClick={handleCloseDrawer}
variants={overlayVariants}
/>
)}
</AnimatePresence>
Ca艂o艣膰 musimy owrapowa膰 wspomnianym wcze艣niej <AnimatePresence/>. Nast臋pnie div zamieniamy na struktur臋 <motion.div, dzi臋ki czemu otrzymamy funkcjonalno艣ci framer motion. Do props贸w initial, animate i exit musimy przypisa膰 odpowiednie animacje. Animacje te zostan膮 pobrane z obiektu overlayVariants, kt贸ry musimy przekaza膰 do propa variants. Poszczeg贸lne propsy odpowiadaj膮 za:
  • initial - stan pocz膮tkowy komponentu
  • animate - jakie w艂asno艣ci elementu maj膮 zosta膰 zanimowane - w naszym przypadku opacity ma zosta膰 zanimowane od warto艣ci 0 do warto艣ci 1
  • exit - jaka animacja ma zosta膰 odpalona na usuni臋cie elementu z DOM. W naszym przypadku b臋dzie to animacja ze stanu visible do hidden
Tyle jest wystarczaj膮ce, aby otrzyma膰 艂adn膮 animacj臋 pojawiania si臋 i znikania overlaya.
Przejd藕my teraz do g艂贸wnej animacji otwierania drawera.
Musimy stworzy膰 kolejny obiekt typu Variants, tym razem dla animacji otwierania i zamykania drawera:
const variants: Variants = {
inactive: { y: 0 },
active: { y: '-80%' },
};
W Drawerze animowana b臋dzie pozycja. Na pocz膮tku na ekranie widoczny b臋dzie przycisk do otwarcia drawera i kawa艂ek tre艣ci, a po otwarciu zmienimy warto艣膰 y komponentu, aby by艂 widoczny na 80% ca艂ej strony.
R贸wnocze艣nie chcemy, aby drawer otwiera艂 i zamyka艂 si臋 na gest poci膮gni臋cia w g贸r臋/poci膮gni臋cia w d贸艂. Musimy zatem stworzy膰 funkcj臋, kt贸ra b臋dzie rozpoznawa艂a w jaki spos贸b u偶ytkownik wykona艂 gest drag:
const handleDragEnd = (_: unknown, info: PanInfo): void => {
if (info.offset.y < 0 && info.offset.y < -80) {
setOpen(true);
}
if (info.offset.y > 0 && info.offset.y > 80) {
setOpen(false);
}
};
W obiekcie info znajduj膮 si臋 wszystkie potrzebne dane dotycz膮ce wykonanego gestu. Funkcja nazywa si臋 handleDragEnd, poniewa偶 musimy obs艂u偶y膰 tylko koniec wykonania gestu. Za pomoc膮 info.offset wiemy dok艂adnie o jakie warto艣ci drawer zosta艂 przesuni臋ty. Nie chcemy, aby za ka偶dym gestem drawer si臋 otwiera艂 b膮d藕 zamyka艂, dlatego dodajemy bufor w postaci 80px, czyli je偶eli u偶ytkownik przesun膮艂 za pomoc膮 drag drawera o wi臋cej ni偶 80px, to znaczy, 偶e chce otworzy膰 b膮d藕 zamkn膮膰.
Taka konfiguracja jest wystarczaj膮ca, aby m贸c zaktualizowa膰 nasz膮 struktur臋 HTML:
<motion.div
className={'drawer'}
dragElastic={0.8}
onDragEnd={handleDragEnd}
dragConstraints={{ top: 0, bottom: 0 }}
drag="y"
>
<motion.div
className={'drawerInner'}
transition={{ type: 'spring', duration: 0.8 }}
variants={variants}
initial="inactive"
animate={open ? 'active' : 'inactive'}
>
<DrawerHeader />
<div className='drawer-content'>
{/* Placeholder for content */}
</div>
</motion.div>
</motion.div>
Om贸wili艣my wcze艣niej ju偶 propsy typu variants, initial i animate, wi臋c tutaj skupimy si臋 bardziej na obs艂udze drag. Jak mo偶na zauwa偶y膰, odpowiada za to kilka warto艣ci:
  • drag="y" - definiuje nam, w kt贸r膮 stron臋 u偶ytkownik mo偶e przeci膮ga膰. U nas tylko w pionie (g贸ra-d贸艂)
  • dragConstraints - definiuje nam granice, za jakie element mo偶e zosta膰 przeciagni臋ty. My blokujemy w taki spos贸b, aby nie mo偶na by艂o wyj艣膰 poza g贸r臋 i d贸艂.
  • onDragEnd - metoda odpalaj膮ca si臋, kiedy u偶ytkownik sko艅czy wykonywa膰 gest - tutaj przekazujemy wcze艣niej zdefiniowan膮 funkcj臋
  • dragElastic i transition - dodatkowe parametry animacji. Zach臋cam do zabawy z nimi!

Rezultat ko艅cowy

I to by by艂o na tyle. Jak wida膰, nie potrzeba du偶o skomplikowanego kodu, aby uzyska膰 艂adn膮, p艂ynn膮 i wydajn膮 animacj臋. Oto prezentuje si臋 efekt ko艅cowy:
FramerMotionAnimationDrawer
Ca艂y projekt dost臋pny jest na githubie: https://github.com/dawidkostrzewa/drawer-framer-motion

Zobacz wi臋cej wpis贸w