Frontend

Fizyka na frontendzie. Jak sprężyny mogą pomóc w tworzeniu efektownych animacji

Animacje css vs. react spring - zobacz różnice, tutorial i stwórz animację

Zanim jeszcze całkiem pochłonął mnie front-end, miałem okazję studiować fizykę. Nie zawsze było mi z nią po drodze, ale muszę jej oddać to, że żadna inna nauka jaką znam, nie jest w stanie tak opisać otaczającego nas świata jak ona. W aplikacjach internetowych natomiast od zawsze pasjonowały mnie animacje. Internet jest przepełniony ich kreatywnymi przykładami, a ja za każdym razem, gdy na taki przykład trafiam, zastanawiam się: Jak coś takiego zrobić? Jak taka animacja wpływa na użytkownika aplikacji? Co mogę zrobić, żeby wyglądała bardziej naturalnie i przyjaźnie?

#top_oferta: Fintech Consultant / Manager

30000 - 50000 pln

Aplikuj

Mikołaj Żywczok. Z wykształcenia fizyk, z zamiłowania programista. Obecnie front-end developer w Ericsson. Poza kodowaniem fascynuje go design, UX i dobra kawa. Prywatnie mąż, pasjonat sztuk walki, akrobatyki i gry na gitarze.


Odpowiedzi na wiele z moich pytań znalazłem w dniu, w którym natrafiłem na bibliotekę react-spring. Pozwala ona tworzyć piękne animacje, wykorzystując do tego fizyczne właściwości sprężyny. Animacja stworzona w ten sposób jest płynna i naturalna – znacznie lepiej oddaje ruch, do którego jesteśmy przyzwyczajeni obserwując otaczający nas świat.

CSS vs. react-spring – porównajmy animacje

Żeby nie być gołosłownym, porównajmy dwie analogiczne animacje, z których pierwsza została stworzona tradycyjnie za pomocą CSS, a druga korzystając z react-spring:

Animacja stworzona w CSS w sumie jest w porządku, ale „szału nie robi” i wygląda raczej sztucznie. Brakuje jej płynności i naturalności, którą widać na drugiej animacji; tego magicznego składnika, który sprawia, że coś wygląda dla nas lepiej nawet jeśli nie zawsze potrafimy wytłumaczyć, dlaczego. Są to detale, o których rzadko myślimy, pracując nad dużymi projektami, ale najczęściej to właśnie one zadecydują o tym, czy nasz produkt zostanie przez użytkownika pokochany, czy będzie on w jego odczuciu jedynie poprawny i funkcjonalny.

W Ericsson zależy nam na tym, żeby produkty, które tworzymy były wzorcowe i dlatego każdy detal ma znaczenie. Skoro wciąż czytasz ten tekst (co mnie bardzo cieszy), to założę się, że myślisz podobnie.

Zmienne CSS i react-spring, jakie są różnice w modelowaniu?

Żeby lepiej zrozumieć skąd biorą się te różnice w odbiorze, przyjrzyjmy się sposobowi opisu animacji tworzonej za pomocą CSS oraz react-spring. Zmienne w CSS, które możemy wykorzystać do manipulowania animacją to:

  1. Duration określa czas trwania liczony od początku do końca animacji.
  2. Easing – parametr pozwalający przyspieszyć lub zwolnić animacje odpowiednio na jej początku bądź końcu.

To wszystko. Tworząc animację z wykorzystaniem wyłączenie CSS-a możemy jedynie określić,
w którymś momencie przyspieszyć bądź zwolnić. W przypadku biblioteki react-spring, która do opisu animacji korzysta z modelu matematycznego sprężyny, mamy trzy parametry służące do modelowania naszej animacji:

1. Masa – odnosi się do wagi poruszającego się elementu. Cięższe elementy będą poruszać się wolniej, ale z większą bezwładnością.

2. Napięcie – odnosi się do energii skumulowanej podczas naciągania sprężyny. Im większa jej wartość, tym animacja będzie bardziej dynamiczna i sprężysta.

3. Tarcie – dotyczy nie tyle samej sprężyny co otoczenia, w jakim się ona znajduje. Przykładowo, naciągnięta sprężyna zanurzona w smole będzie przez nią skutecznie hamowana (duże tarcie), przez co ruch szybko się zakończy. Gdybyśmy natomiast wysłali ją w kosmos, gdzie znalazłaby się w próżni (zerowe tarcie) to jej ruch trwałby w nieskończoność.

Myśląc o zastosowaniu fizycznych właściwości sprężyny w tworzeniu animacji wydawałoby się, że będziemy w stanie uzyskać w ten sposób jedynie skoczne, sprężynujące efekty, ale nic bardziej mylnego, możliwości tworzenia animacji z react-spring są znacznie większe! Zobaczcie sami:

React-spring tutorial – stwórzmy własną animację!

A teraz, uzbrojeni w całą potrzebną teorię, zobaczmy jak z tradycyjnej animacji CSS zrobić coś wyjątkowego!

via GIPHY

Codesandbox: Raise.js

Uff, trochę tego jest, ale spokojnie, zaraz przejdziemy przez niego i wyjaśnimy sobie, o co w nim chodzi. Animacja polega na tym, że po najechaniu kursorem myszy na dany element, ten się unosi. Dodatkowo, w tym samym momencie rusza timer, który po upływie określonego czasu daje sygnał elementowi, żeby ten wrócił do swojego stanu początkowego (nawet jeżeli nasz kursor wciąż znajduje się nad elementem). Informacja o stanie w jakim znajduje się nasz element przechowywana jest w zmiennej isRaised.

Codesandbox: Raise.js

Najechanie kursorem nad animowany element sprawia, że wartość isRaised zmienia się na true, co z kolei aktywuje naszą animację, a także hook useEffect, w którym zostaje nastawiony timer, odliczający czas, po którym wartość zmiennej isRaised zostaje zmieniona z powrotem na false.

Sam efekt polega na zastosowaniu transform: translateY. Wysokość, na którą ma się unieść element, a także czas trwania animacji możemy kontrolować za pomocą przesłanych propsów ( height i timing). Dodatkowo ustawiamy display: inline-block (na elementach display: inline animacja by nie zadziałała), a także backface-visibility: hidden (dzięki temu pracę potrzebną do wyrenderowania naszej animacji zrzucamy na procesor graficzny, co z kolei przekłada się zwiększenie jej płynności).

Codesandbox: Raise.js

Animowany element, otaczamy tagiem span. Zapytacie pewnie:

– Dlaczego akurat span skoro, każdy szanujący się frontendowiec wie, że eventy powinny być obsługiwane w widocznych elementach, takich jak choćby button? Przecież span jest niemożliwy do zaznaczenia korzystając z klawiatury, a my chcemy pisać kod dostępny dla każdego!

Odpowiem Wam:

via GIPHY

Jednakże, w tym przypadku, animacja, którą rozważamy ma charakter czysto wizualny i podejrzewam, że mogłaby być irytująca dla osób poruszających się po stronie za pomocą klawiatury.

Stworzonego przez nas komponentu możemy użyć w następujący sposób:

Codesandbox: App.js

Wszystko wyjaśnione, wiemy już jak działa nasz kod, a animacja wygląda w porządku. Jest nieźle, ale wiem, że stać nas na więcej! Doprawmy naszą animację odrobiną magii z pomocą react-spring.

via GIPHY

Codesandbox: Raise.js

Co się zmieniło? Po pierwsze, z biblioteki react-spring importujemy useSpring i animated. Hook useSpring pozwala nam opisać animacje korzystając z modelu matematycznego sprężyny, zamiast używanych w CSS krzywych Béziera. Jako parametr przesyłamy do niego obiekt z naszymi lekko zmodyfikowanymi stylami (linijkę z kodem transition: transform, zamieniamy na obiekt config, zawierający w sobie informacje na temat masy, napięcia i tarcia). Jako że opisywanie animacji w ten sposób, nie jest wspierane przez przeglądarki (jeszcze), nie możemy takiego obiektu przekazać bezpośrednio tagowi &lt;span&gt;. Tutaj do akcji wkracza animated, który możemy wykorzystać do stworzenia tagu &lt;animated.span&gt;. Działa on w sposób analogiczny do zwykłego <span> z tą jednak różnicą, że potrafi rozszyfrować nasz nowy sposób opisu animacji. Oto efekt końcowy, gratulacje!

Jakie jeszcze możliwości daje react-spring?

Przykładowo, nasz komponent można również prostym sposobem przerobić na hook, co przyda nam się szczególnie w przypadku, w którym mając dwa różne elementy. Chcielibyśmy, żeby jeden z nich aktywował animacje tego drugiego (co w przypadku naszego aktualnego komponentu jest niestety niemożliwe).

Codesandbox: useRaise.js

Do naszego hooka całą konfigurację animacji przesyłamy w parametrze, on przeprowadza dla nas odpowiednie obliczenia, a następnie zwraca tablicę zawierającą obiekt ze stylem animacji oraz trigger, za pomocą którego możemy ją aktywować. Zostało nam już tylko go użyć:

Codesandbox: App.js

Obiekt style przypisujemy do elementu, który chcemy animować, a trigger do elementu, który ma tę animację wywołać i gotowe. A teraz najlepsze – nasz hook jest ekstra, ale jeśli woleliśmy używać wcześniejszego komponentu, a sytuacja nam na to pozwala, to przecież wcale nie musimy z niego rezygnować. Dodatkowo, wykorzystując nasz hook możemy go odrobinę odchudzić.

Codesandbox: Raise.js

W efekcie możemy korzystać z naszej animacji na dwa sposoby, a cały kod pozostaje zwięzły i wolny od niepotrzebnych duplikatów. W moim odczuciu react-spring sprawia wrażenie biblioteki bardzo dobrze przemyślanej – jest wydajna, prosta w obsłudze i wszechstronna. Można z niej korzystać zarówno poprzez nowoczesne hook API (tak jak zrobiliśmy to my), jak i class API, w zależności od preferencji i potrzeb developera. Całym sobą zachęcam do eksperymentowania z tą biblioteką, ponieważ jej potencjał jest ogromny (po odrobinę inspiracji odsyłam do sekcji z przykładami na oficjalnej stronie).

Na zakończenie…

Dziękuję za czas, który mi poświęciłeś (mam nadzieje, że w twoim odczuciu nie był to czas stracony). Daj proszę znać, co myślisz na temat tego tekstu w komentarzu lub pisząc do mnie na LinkedInie, a jeśli w trakcie czytania nasunęły Ci się jakieś pytania, też chętnie na nie odpowiem.

Pomyślnego kodowania!


Zdjęcie główne artykułu pochodzi z unsplash.com.

Frontend Developer w Ericsson

Z wykształcenia fizyk, z zamiłowania programista. Obecnie front-end developer w Ericsson. Poza kodowaniem fascynuje go design, UX i dobra kawa. Prywatnie mąż, pasjonat sztuk walki, akrobatyki i gry na gitarze.

Podobne artykuły