4/12/2022 ∙ 5 minut czytania
Podstawowe animacje 🎬
Pewnie nie jest to najlepszy moment na implementację animacji w kodzie tej strony. Jest dużo ważniejszych rzeczy do zrobienia, ale bloga prowadzę przede wszystkim dla przyjemności i uznałem, ze przesunę w czasie ważniejsze kroki i dodam do swojej strony drobne animacje.
Animacje w tailwind
W kodzie strony została juz zaimplementowana bardzo podstawowa obsługa trybu ciemnego. Więcej informacji na ten temat można znaleźć w tym artykule. Tutaj zajmę sie drobna aktualizacja sposobu w jaki można te elementy animować:
app/root.tsx
:
<body className="bg-white transition duration-300 dark:bg-slate-800">
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
Powyższy kod odpowiada za zdefiniowanie podstawowej tranzycji na każdej stronie.
Właściwości na których będzie działać tranzycja pokażą sie po najechaniu na
klasę transition
i wygląda to następująco:
.transition {
transition-property: color, background-color, border-color,
text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter,
backdrop-filter;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
jak widać animujemy wszystkie zmiany kolorów. Domyślnie długość tranzycji trwa
150ms, a dzięki klasie .duration-300
nadpisujemy ją na 300ms:
.duration-300 {
transition-duration: 300ms;
}
Powyższe dodanie jedynie dwóch klas, czyli transition
oraz .duration-300
ustawia podstawowe parametry tranzycji, które aplikują sie na wszystkie kolejne
podstrony. Zmiana z trybu ciemnego na jasny i odwrotnie, z poziomu ustawień
systemowych systemu operacyjnego na którym pracujemy, spowoduje, ze zobaczymy te
animacje.
Animacje framer-motion
Framer-motion to biblioteka, dzięki której możliwe jest deklaratywne pisanie animacji za pomocą komponentów, a właściwie proksów, które biblioteka udostępnia programiście. Cala warstwa abstrakcji utrudniających prace z animacjami jest przed nami ukryta za fasada bardzo prostego interfejsu. Instalacja paczki przebiega nad wyraz standardowo:
npm i framer-motion
Użycie paczki:
Paczka jest użyta póki co w dwóch miejscach. Na stronie głównej oraz na stronie artykułu.
Po wejściu na stronę główna można zauważyć animacje pojawiającego sie tytułu, a pod nia listy ostatnich artykułów. Całość ma fajny efekt, bo kolejne elementy listy pojawiają sie jeden pod drugim w formie wjeżdżających z lewej strony elementów.
Odpowiada za to bardzo prosty kod, który postaram sie tutaj wyjaśnić. Ważna
uwaga - pomijam tutaj wszystkie elementy kodu, które nie sa bezpośrednio
powiązane z paczka framer-motion
.
Krok pierwszy - importy
import { Variants, motion } from 'framer-motion'
motion
- podstawia biblioteki, jest agregatem gotowych elementów HTML które posiadają dodatkowe props'y odpowiadające za animacje.Variants
- jest to deklaracja typów, która określa strukturę etapów w jakich może znaleźć sie animowany element.
Krok drugi - animacja elementu h1
z napisem "Blog"
Weźmy pod lupe pierwszy, bardzo prosty element, czyli header z napisem "Blog":
const header: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
duration: 0.5,
},
},
}
;<motion.h1
// ...
variants={header}
initial="hidden"
animate="visible"
>
Blog
</motion.h1>
Header posiada dwa stany (ukryty i widoczny). Element motion.h1
posiada
dodatkowe props'y, które ułatwiają konfiguracje elementu:
variants
- prop do którego przekazujemy warianty w jakich może byc elementinitial
- ustawia stan początkowy elementu.animate
- ustawia stan do którego animujemy element po jego wyrenderowaniu.
Możemy doprecyzować ile czasu ma trwać tranzycja, w jaki sposób powinna wyglądać
charakterystyka animacji i za to odpowiada konfiguracja pod zmienna header
.
Dzięki deklaracji typów Variant
działa automatyczne podpowiadanie, które
znacząco ułatwia prace z kodem.
Krok drugi - animacje elementów listy
Za ciekawy efekt opóźnienia animacji kolejnych elementów listy odpowiada
odpowiednia konfiguracja zmiennej list
.
const list: Variants = {
visible: {
transition: {
staggerChildren: 0.03,
delayChildren: 0.2,
},
},
}
;<motion.ul
//...
variants={list}
initial="hidden"
animate="visible"
>
{/* ... */}
</motion.ul>
jak widać, interesuje nas tylko przejście do tranzycji visible
, która zostanie
wykonana po wyrenderowaniu elementu motion.li
. W tym momencie zostanie
wykonana animacja dla każdego elementu listy. Nie ma tutaj definicji tego jak
dany element listy ma sie zachować. Definiujemy tutaj jedynie opóźnienie dla
kolejnych elementów listy.
Każdy element listy ma swoja własną animacje, którą wspólny rodzic każdego z
nich (motion.ul
) będzie orkiestrował. W tym przypadku będzie to odpowiednie
opóźnienie w czasie. Dzięki czemu nie musimy juz przypisywać wartości do propsow
initial
oraz animate
na każdym elemencie osobno. Za całość odpowiada lista.
Jedynym ważnym aspektem jest to, żeby warianty zarówno listy (motion.ul
) oraz
elementów listy (motion.li
) miały takie samo nazewnictwo:
const item: Variants = {
hidden: { opacity: 0, x: -10 }, // zacznij od opacity 0 i przesunięcia w lewo o 10px
visible: { opacity: 1, x: 0 }, // skończ na opacity 1 i przesuń w prawo na pozycje 0
}
;<motion.li
// ...
variants={item}
>
{/* ... */}
</motion.li>
Krok trzeci - animacja artykułu pojawiającego się na stronie
Tutaj sprawa działa analogicznie jak w przypadku listy oraz nagłówka. Jednak tym razem charakterystyka animacji wygląda nieco inaczej:
const variants: Variants = {
// zacznij od opacity 0 i przesunięcia w górę o 20px
hidden: {
opacity: 0,
y: -20,
},
// skończ na opacity 1 i przesuń w dół na pozycję 0
visible: {
opacity: 1,
y: 0,
// animacja ma trwać 0.5s a jej przebieg ma byc określony funkcją typu "easeOut"
transition: {
ease: 'easeOut',
duration: 0.5,
},
},
}
;<motion.article
// ...
variants={variants}
initial={'hidden'}
animate={'visible'}
>
{/* ... */}
</motion.article>
Więcej o przebiegach animacji można poczytać tutaj.
> exit
Poniżej znajdziesz więcej postów, które mogą Cię zainteresować.