Animacje
Chcieć opisać animacje stosowane na stronach, to jak próbować opisać gatunek ludzki i wszelkie jego zawiłości w jednym artykule. Praktycznie niewykonalna sprawa.
Zacznijmy od najprostszych tematów czyli animacji CSS i ich obsługi w Javascript.
Dzielimy je na dwie kategorie: płynne zmiany dzięki właściwości transition oraz klasyczne animacje tworzone za pomocą właściwości animation i składni @keyframes.
Transition
Właściwość transition po użyciu na elemencie sprawia, że gdy zmieni on swoje właściwości, takie zmiany będą dziać się płynnie.
Ogólna konstrukcja transition ma postać:
/* poszczególne właściwości */
transition-property: width, height; /* właściwości, których zmiany mają być płynne. Możemy wypisać kilka po przecinku, możemy też użyć domyślnej "all" co oznacza wszystkie właściwości */
transition-duration: 2s; /* jak długa ma być ta zmiana. Możemy podać w s lub ms */
transition-timing-function: linear; /* typ animacji - ease, ease-in, ease-out, ease-in-out, cubic-bezier */
transition-delay: 1s; /* opóźnienie rozpoczęcia */
/* wersja shorthand */
/* jeżeli szerokość się zmieni, to animacja będzie trwać 2s, z 1s opóźnieniem, a przebieg animacji będzie stały (linear) */
transition: width 2s 1s linear;
/* jeżeli tło się zmieni, to będzie to animowane 2s */
transition: 2s background;
/* jeżeli szerokość się zmieni, będzie to trwać 1s */
/* jeżeli dany element zostanie transformowany, będzie to trwać 2s z opóźnieniem 1s */
transition: 1s width, 2s 1s transform;
/* jeżeli cokolwiek się zmieni to zmiana będzie trwać 1s */
transition: 1s;W większości przypadków (chociaż nie we wszystkich) wystarczy ostatni - najkrótszy zapis.
Nie jest to rozwiązanie na każdą sytuację. Jeżeli dla przykładu w widoku mobilnym chciałbym, by powyższy przycisk zajmował całą szerokość, zmiana taka także była by płynna, czego raczej bym nie chciał. Dlatego w wielu przypadkach lepiej wypunktować właściwości, które mają się płynnie zmieniać np.: transition: 1s background, 1s border-radius.
Dość często transition jest stosowana dla elementów, dla których stosujemy :hover czy :focus. Nie musimy jednak ograniczać się tylko do tych stanów. Zmiany danej właściwości mogą być wprowadzone na różne sposoby - np. poprzez dodanie nowej klasy czy chociażby za pomocą setInterval()
Lorem ipsum dolor sitLorem ipsum dolorLorem ipsum dolor sitLorem ipsum
Właściwość transition (ale też poniższe animacje) zadziała tylko z tymi właściwościami, które mogą się zmieniać stopniowo (np. zwiększając swój rozmiar). I tak dla przykładu właściwość width bez problemu zmienimy z 100px na 150px, color z #fff na #ddd, a opacity z 0 na 1. Ale już display z block na none, czy font-weight: bold na normal nie. Trzeba wtedy sięgnąć po inne techniki:
Warto też zwrócić uwagę na właściwość transition-delay, ponieważ pozwala ona tworzyć dość ciekawe efekty:
Zrób zakupyTaguj kogośOdbierz paczkęPopraw błędy#
Zdarzenia dla transition
Jeżeli chodzi o Javascript i właściwość transition, to mamy do użycia zdarzenia:
transitionrun
odpalane gdy transition zostało uruchomione, ale niekoniecznie jeszcze się animuje (bo użyta jest właściwość transition-delay)
transitionend
odpalane gdy transition się zakończyło
transitioncancel
odpalane gdy transition zostało przerwane (programowo)
Animation
Właściwość animation służy do podpinania do elementu animacji.
Wpierw opisujemy przebieg animacji za pomocą składni @keyframes. Przypomina to stawianie kluczowych klatek na osi czasu - znane praktycznie z każdego programu do obróbki video. W zakresie 0% - 100% opisujemy miejsca, w których możemy zmieniać wiele właściwości na raz:
Składnia @keyframes ma postać:
Następnie opisaną w ten sposób animację (lub kilka animacji podając je po przecinku) możemy podpiąć do elementu za pomocą właściwości:
Przykład prostej animacji:
Przy opisywaniu miejsc w @keyframes możemy też użyć słów kluczowych from i to, a także opisywać procentowe miejsca w dowolnej kolejności. Stworzona w ten sposób animacja będzie płynnie zmieniać dane właściwości w czasie. Jeżeli w konkretnym jej momencie chcemy skokową zmianę, powinniśmy utworzyć dwa punkty bardzo blisko siebie:
Nie dla każdego zabawy z animacjami są przyjemnością. Czasami więc warto skorzystać z gotowych zestawów:
Zdarzenia dla animation
Od strony Javascript mamy dostęp do kilku zdarzeń związanych z animacjami:
animationiteration
gdy pojedyncze powtórzenie animacji się zakończy i zacznie się odtwarzanie kolejnego
animationcancel
odpalane gdy odgrywanie animacji zostanie niespodziewanie przerwane
animationend
odpalane gdy animacja się zakończy
Jeżeli są to animacje, które mają się odegrać tylko jeden raz, warto pamiętać, że dla zdarzeń mamy 3 parametr, w którym możemy określić, że dana funkcja zadziała tylko jeden raz:
Co warto animować
Zanim przejdziemy dalej, warto chwilę się zatrzymać przy tym co możemy i powinniśmy animować.
Żeby to zrozumieć, prześledźmy jak w ogóle powstaje obraz naszej strony. Składa się ono z kilku faz.
Na samym początku jest tak zwane parsowanie kodu strony czyli czytanie kodu dokumentu i na jego podstawie układanie drzewa DOM. W tym momencie przeglądarka jeszcze nie wie jak te elementy będą wyglądać, a skupia się tylko na ich zależnościach.
W kolejnym kroku następuje aplikowanie styli do elementów.
Następnie przeglądarka sprawdza rozmiar elementów, tworzy dla nich "pudełka" (model pudełkowy) i odpowiednio je układa na stronie tworząc layout.
W kolejnym kroku pudełka są rysowane. Pudełka mogą być zgrupowane na oddzielnych warstwach (w zależności od tego czy użyliśmy odpowiednich właściwości w CSS).
Na samym końcu przeglądarka pobiera różne warstwy, aplikuje na nie kompozycyjne właściwości (takie jak np. transform) i rysuje na ekranie.
Całość można przyrównać do tworzenia grafiki 3d w np. Blenderze. Na początku czytasz z kartki swój pomysł. Potem modelujesz, układasz elementy, ustawiasz im wielkość itp. Jak już wszystko ułożysz, renderujesz obraz. Na samym końcu poddajesz taki obraz dodatkowej obróbce, czyli kompozycji. Układanie i modelowanie elementów to pracochłonna rzecz zajmująca często kilka godzin, dni a nawet tygodni. Renderowanie takiego obrazu też często zajmuje naście godzin (żeby...). Natomiast sama kompozycja to w zasadzie dodatek, który po odpowiedniej konfiguracji aplikowany jest na przygotowany obraz praktycznie natychmiastowo. Jak chcesz się o tym przekonać (a i zwiększyć swoje kompetencje) - zapraszam do jednego z ciekawszych tutoriali na te tematy. Szczerze polecam, bo zabawa przednia, a i w nadchodzących czasach praca ze światem 3d będzie w "meta cenie").
W przeglądarce działa to podobnie. Jeżeli np. wrzucisz na stronę za pomocą Javascript nowy kawałek html, przeglądarka będzie musiała wykonać wszystkie fazy - od parsowania do kompozycji.
Animowanie wielu właściwości (np. width, font-size) spowoduje, że przeglądarka będzie musiała dane elementy ponownie ułożyć, obliczyć jego pozycję i ponownie narysować. Niektóre właściwości nie zmienią ułożenia elementów (np. background-position) więc przy ich animowani przeglądarka nie będzie musiała wrócić do układania elementów, a tylko do ich przerysowania. Najmniej obciążające dla przeglądarki są właściwości, których rysowanie odbywa się w fazie kompozycji. Są to wszelkie transformacje transform oraz właściwość opacity (pełną listę znajdziesz tutaj). Dla nas oznacza to tyle, że animowanie tych właściwości jest zazwyczaj o wiele płynniejsze niż innych właściwości.
Nie zrozum mnie źle. Animować możesz praktycznie wszystko (i nie bój się tego!), po prostu testuj efekt końcowy. Gdybyśmy mogli polegać tylko na transform i opacity, w zasadzie nie było by mowy np. o zwijanych panelach, czy innych znanych efektach.
Dodatkowe informacje: https://www.youtube.com/watch?v=0Xg6r_MKGJ4 i w tym artykule.
Web Animation API
Powyższe właściwości mimo, że mają olbrzymią moc, nie zawsze będą wystarczające, a przy niektórych bardziej złożonych animacjach użycie samego CSS staje się wręcz zadaniem nierozwiązywalnym (szczególnie gdy chcemy mieć na stronie kilka zapętlonych zależnych od siebie animacji).
W dzisiejszych czasach do animacji możemy podejść na kilka sposobów:
możemy próbować animować z wykorzystaniem setInterval. Obecnie metoda ta wykorzystywana jest raczej przy zabawach z canvas i webgl, lub wszędzie tam gdzie potrzebujemy losowości.
możemy też to co się da animować w CSS, a w JS umiejętnie dodawać tylko odpowiednie klasy i ewentualnie reagować na odpowiednie zdarzenia. Metoda fajna przy prostych animacjach, ale raczej zawiedzie przy czymś bardziej skomplikowanym
w końcu możemy sięgnąć po odpowiednie biblioteki do animacji takie jak Green Sock (najlepsza w swoim fachu), http://animejs.com/ czy chociażby jQuery (plus naście innych).
W czystym Javascript przez wiele lat animacje były traktowane mocno po macoszemu. Sprawa zaczęła się zmieniać w ostatnich latach za sprawą tak zwanego Web Animate API, którego zadaniem jest utworzenie jednego standardy scalającego dwa światy - animacje tworzone w Javascript i CSS.
Cały mechanizm składa się z 3 kluczowych części: osi czasu, tak zwanych efektów, oraz obiektów animujących.
Osie czasu. Każdy dokument ma swoją oś czasu, która rozpoczyna się w momencie wczytania strony a kończy w nieskończoności. Na takiej osi układane są twoje animacje. W chwili pisania tego tekstu dla każdego dokumentu mamy dostęp tylko do jednej - głównej osi czasu document.timeline. Działa ona zupełnie tak samo jak w przypadku animacji CSS. Odpalamy animację i jest ona po prostu odgrywana w jakimś czasie. W przyszłości zapowiedziane są też inne rodzaje osi. Przykładowo postęp naszej animacji będzie zależny od przewinięcia strony czy innych gestów (a że świat mocno wchodzi w świat wirtualny...). Można to więc przyrównać do tego co już niedługo będziemy wyczyniać za pomocą CSS (1, 2, 3).
Efekty (AnimationEffect) to obiekty, które opisują przebieg animacji, czyli dla jakiego elementu w jaki sposób dane właściwości mają być animowane. Są więc zestawem informacji podobnych do CSSowego zapisu @keyframes i właściwości animation-. W chwili obecnej mamy tylko jeden typ efektów czyli KeyframeEffect (tak samo w CSS mamy tylko @keyframes). W przyszłości zapowiedziane są efekty pozwalające łączyć animacje, czy odpalać je sekwencyjnie (ale o tym później).
Same animacje (Animation) są z kolei obiektami, które scalają wszystko w całość pozwalając wreszcie odpalać naszą upragnioną animację. Przy ich tworzeniu musimy przekazać im zarówno efekty jak i oś, która zostanie użyta do odgrywania.
Tyle teorii - przejdźmy do praktyki.
Dodawanie animacji
Aby utworzyć animację, musimy zebrać wszystkie niezbędne informacje: jaki element ma być animowany, jak ma być odtwarzana animacja, oraz jaka oś ma być użyta do odtworzenia.
Możemy to osiągnąć korzystając z konstruktora Animation() oraz ze skróconego zapisu element.animation(). Zacznijmy od tego drugiego sposobu, bo prawdopodobnie to z niego będziesz najczęściej korzystał.
Aby dodać animację do elementu - podobnie jak w CSS musimy stworzyć opis animacji, a następnie podpiąć ją pod dany element.
Przy definiowaniu klatek animacji możemy skorzystać z właściwości offset, która przyjmuje wartość od 0 do 1. Właściwość ta określa moment na osi czasu i jest tym samym co zapis procentowy dla @keyframes w CSS.
W odróżnieniu od CSS możemy też określać konkretne przejścia kolejnymi punktami animacji:
Najczęściej właściwość ease będziesz przekazywał w obiekcie opcji, co spowoduje, że będzie ona aplikowana na całą animację.
Jest jeszcze kilka wariantów opisu klatek, natomiast najczęściej spotkasz się z powyższym.
Jeżeli chcemy odtworzyć animację tylko jeden raz z domyślnymi parametrami, możemy też nie podawać żadnych opcji, a zamiast nich przekazać czas w milisekundach:
Do pojedynczego elementu możemy podłączyć w ten sposób dowolną liczbę animacji.
Funkcje zwrotne, właściwości i metody
W przypadku tak utworzonych animacji mamy dostęp do kilku funkcji zwrotnych:
Kilku dodatkowych metod:
animation.commitStyles()
zaaplikuj elementowi końcowe style animacji. Style zostaną zapisane w atrybucie style
animation.finish()
przerwij odtwarzanie animacji, przejdź do końca animacji (nie można przerwać nieskończonych animacji)
animation.pause()
pauzuje odtwarzanie
animation.play()
wznów odtwarzanie animacji
animation.reverse()
odgrywając do tyłu cofa animację do momentu kiedy zaczęła się odgrywać (animacja zatrzyma się w momencie kiedy wystartowała). Podobne efekty daje animation.playbackRate = -animation.
animation.updatePlaybackRate()
ustawia szybkość odtwarzania animacji tuż po pierwszej synchronizacji pozycji odtwarzania
Oraz kilku właściwości:
animation.effect
zwraca lub ustawia zestaw AnimationEffect powiązany z tą animacją
animation.finished
zwraca true/false czy dana animacja zakończyła odtwarzanie
animation.id
zwraca id animacji w postaci tekstu
animation.pending
tylko do odczytu - czy dana animacja oczekuje na asynchroniczną operację (pauzowanie lub włączenie odtwarzania)
animation.playState
tylko do odczytu - zwraca lub ustawia stan animacji (idle, running, paused, finished)
animation.playbackRate
zwraca lub ustawia szybkość odtwarzania animacji
animation.ready
tylko do odczytu - zwraca obietnicę czy dana animacja jest gotowa do odtworzenia
animation.replaceState
tylko do odczytu - zwraca czy dana animacja została podmieniona
animation.startTime
pobiera lub ustawia czas kiedy ma się rozpocząć odtwarzanie animacji
animation.timeline
pobiera lub ustawia timeline dołączone do tej animacji
Przykłady
testplay restart finish reverse speed up speed down
Pobieranie animacji ze strony
Funkcja document.getAnimations() służy do pobrania animacji, które ustawiliśmy za pomocą animation API ale też i CSS.
Sprawdź w konsoli
Gdy odpalisz powyższy kod, zobaczysz w konsoli, że na tej stronie jest użytych kilka typów animacji. Część z nich jest typu CSSAnimation, niektóre to Animation, a z kolei inne to CSSTransition. Łatwo się domyślić, że część z wymienionych w konsoli obiektów to animacje użyte w powyższych przykładach, transition z kolei to efekt przejścia tła dla przycisku.
Dla każdej takiej animacji możesz korzystać z wymienionych powyżej właściwości i metod, np. zatrzymując wszystkie animacje na stronie.
Podobną funkcję możemy też odpalić dla każdego elementu z osobna:
Po kliknięciu na poniższy element dodaję mu animację CSS, animację Javascript oraz transition, a następnie wypisuję je w konsoli.
Konstruktor Animation()
Animację możemy też utworzyć za pomocą konstruktora Animation(), do którego musimy przekazać obiekt z efektami, a także oś jaka zostanie użyta do odtwarzania (domyślnie będzie użyta oś document.timeline).
Gdy w powyższym przykładzie zbadasz w konsoli wypisane elementy, zauważysz, że wśród ich właściwości znajduje się właściwość effect. Wskazuje ona na wspomniane wcześniej efekty zawierające zbiór informacji o tym jaki element jest animowany (effect.target), oraz przebiegu i parametrach odtwarzania animacji. W przypadku powyższych animacji jest to obiekt typu KeyframeEffect.
W skróconej składni opisywaliśmy po prostu wygląd klatek i użytych parametrów. W przypadku konstruktora Animation() musimy wcześniej stworzyć podobny obiekt za pomocą konstruktora KeyFrameEffect():
Utworzony w ten sposób obiekt możemy wykorzystać do utworzenia obiektu z animacją.
Główna różnica w porównaniu do skróconej składni jest taka, że do konstruktora Animation możemy przekazać obiekt z efektami. W przyszłości będziemy mogli tworzyć dodatkowe typy efektów takie jak "grupujące kilka animacji" (GroupEffect) oraz "odpalające animację sekwencyjnie" (SequenceEffects) plus pewnie kilka innych. Na chwilę obecną żadne z tych rozwiązań niestety domyślnie nie zadziała, dlatego aby ich użyć, skorzystam ze skryptu polyfill.
Odtwórz
Niestety na chwilę obecną są to nie tylko oficjalnie nie działające, ale też dość ograniczone rzeczy (np. brakuje tutaj powtarzania takich animacji).
Podsumowanie
Jak widzisz Javascript i CSS dają całkiem spore możliwości jeżeli chodzi o animacje. Mimo to wydaje się, że przy bardziej skomplikowanych projektach raczej nie zastąpią bibliotek takich jak Green Sock czy animejs, która to jest jeszcze wygodniejsza w użyciu i ma większe możliwości (a i lepiej sobie radzą przy animacji svg).
Tak naprawdę w powyższym tekście tylko lekko drasnęliśmy temat animacji. Im dalej w las tym bardziej będziesz się przekonywał, że w dzisiejszych czasach mamy wręcz nieograniczone możliwości w tym temacie.
Z mojej strony mogę ci polecić kilka materiałów, z których sam często korzystam:
https://css-animations.io/ - interaktywny kurs animacji CSS
https://www.youtube.com/channel/UCVyRiMvfUNMA1UPlDPzG5Ow - dobry kanał o UI/UX i animacjach
https://www.youtube.com/watch?v=5DEq5cWNYt8 - kanał Kevina Powella - specjalisty od CSS
https://tympanus.net/codrops/ - jedna z najlepszych stron z tutorialami
https://codepad.co/playgrounds?sortBy=most-liked - kolekcje animacji
https://codepen.io/spark - wybrane efekty z Codepen
A co dalej? Tyle się teraz mówi o Metaverse czy Neurolinku. Wszystko więc wskazuje na to, że dużymi krokami zbliża się kolejna "rewolucja" w internecie. Przykład? https://www.wirtualnemedia.pl/artykul/h-m-sklep-metaverse. Może właśnie umiejętność tworzenia światów 3d i ich animacji będzie jedną z kluczowych? A jeżeli tak - three.js i zabawa z trójwymiarowymi światami to bardzo dobry wybór na kolejne eksperymenty.
Last updated