Okładka artykułu Tworzenie animowanej ilustracji — Za pomocą SVG i CSS
Poradniki

Tworzenie animowanej ilustracji

Za pomocą SVG i CSS

Zdjęcie autora Jarosław Majewski
0

Przez wiele lat Flash wiódł w Internecie prym jeśli chodzi o treści multimedialne, elementy interaktywne oraz animacje. Powstało wiele stron pełnych wspaniałych prezentacji wprowadzających (intro), pięknych przycisków, muzyki w tle oraz animowanych grafik. Internet nie był tak szybki jak dziś, a strony pękały w szwach od treści, tworzono więc preloadery, czyli animacje pojawiające się w czasie oczekiwania na załadowanie plików strony, będące czasem same w sobie małymi dziełami sztuki.

Jednak ciemne chmury zaczęły zbierać się nad Flashem – zwiastunem zmian był brak wsparcia tego formatu w urządzeniach mobilnych. Potem twórcy przeglądarek na urządzeniach stacjonarnych zaczęli także odżegnywać się od wtyczek Flash w swoich produktach. Nawet twórcy się poddali i Adobe Flash nie jest już tym samym programem.

Cóż zatem ma począć grafik, który chce tchnąć nieco życia w projekt i stworzyć na przykład animowaną maskotkę na stronie klienta? Maskotka musi po pierwsze dobrze wyglądać we wszystkich popularnych przeglądarkach, po drugie musi być zoptymalizowana i mało ważyć, a po trzecie – dobrze się prezentować na ekranach o wysokiej rozdzielczości. Dobrze by było, żeby była przyjazna dla wyszukiwarek i mogła zawierać elementy interaktywne. Nie da się? Całe szczęście nie jest tak źle!

SVG na ratunek!

Z pomocą przychodzi format SVG. SVG jest otwartym wektorowym formatem obrazów, opartym na XML i przeznaczonym do wyświetlania w Internecie.

Zalety SVG

Jego głównymi zaletami są:

  • pełna zgodność z HTML w tym możliwość stylowania CSS
  • możliwość optymalizacji rozmiaru pliku
  • możliwość animowania dowolnego atrybutu
  • bardzo duża kompatybilność

Tworzenie ilustracji SVG do animacji

Skoro plik svg jest po prostu graficznym plikiem wektorowym, możemy więc naszą ilustrację stworzyć praktycznie w dowolnym programie graficznym bazującym na grafice wektorowej takim jak: Illustrator, Inkscape czy też Sketch (tylko OS X).

Tworząc grafikę SVG trzeba mieć na uwadze funkcje i ograniczenia tego formatu.

  • Tworząc krzywe używamy jak najmniej punktów, ilustracje powinny być jak najprostsze. Ważne szczególnie jeśli chcemy użyć animacji morfowania kształtu.
  • Unikamy stosowania filtrów w programie graficznym. Jeśli już musimy, stosujemy filtry SVG (dostępne np. w Illustratorze).
  • Gdzie się tylko da stosujemy figury geometryczne – prostokąty, elipsy – po eksporcie do SVG zapisane one będą jako elementy rect oraz circle co ułatwi to potem animację tych elementów i zmniejszy wielkość pliku.

Będziemy pracować w Illustratorze bazując na ilustracji sowy, którą stworzyłem.

Zaczynamy od naszkicowania naszej ilustracji i jej zeskanowania

owl_00

Już na tym etapie procesu należy mieć na uwadze to, które elementy będą animowane i w jaki sposób.

Ja chcę by moja sowa mogła:

  • przesuwać się w pionie, a jej ciało mogło się skalować w pionie i poziomie,
  • jej łapy poruszały się lekko w pionie,
  • głowa poruszała na boki po krzywej, a korpus mógł się obracać,
  • skrzydła obracały się, a ich grafika morfowała się w 4 różne kształty,
  • źrenice poruszały się, a wraz z nimi brwi,
  • oczy mrugały poprzez proste skalowanie w osi Y i pokazanie przez ułamek sekundy grafiki powiek.

Dzięki tym animacjom nauczymy się stosować praktycznie wszystkie techniki animacji plików SVG.

Mając te wszystkie pomysły na uwadze tworzymy nowy dokument Illustratora o wielkości 600 na 400 pikseli i importujemy nasz szkic. Zaczynamy tworzenie ilustracji używając narzędzi Pióro oraz Elipsa. Ważna jest hierarchia warstw i grup, a także odpowiednie ich nazewnictwo, które ułatwia potem rozeznanie się w kodzie, gdyż nazwy użyte w programie będą potem eksportowane jako id elementu.

Plik svg wyeksportowany z Illustratora
Plik SVG wyeksportowany z Illustratora

W sumie już moglibyśmy zacząć animować tak uzyskany plik SVG, jednak spójrzmy co się stanie, gdy na przykład będziemy chcieli zanimować obrót skrzydła…

Źle ustawione warstwy
Źle ustawione warstwy, wizualizacja w formacie GIF

Okazuje się, że punkt wokół którego obraca się skrzydło umiejscowiony jest w lewym górnym rogu pliku SVG. Tak właśnie liczone są współrzędne w pliku. Lewy górny róg jest początkiem osi współrzędnych i każdy element jest transformowany względem tego punktu, nie zaś względem swojego środka jak jest to w przypadku języka HTML oraz CSS. Jak to naprawić? Musimy najpierw zerknąć na naszą listę animacji i zobaczyć jakie elementy chcemy animować i gdzie ma znajdować się ich środek wokół którego liczone będą wszystkie transformacje.

Grupowanie elementów i ich środki
Grupowanie elementów i ich środki

Tak mniej więcej prezentuje się grupowanie elementów i ich środki transformacji oznaczone na rysunku różowymi krzyżykami. Musimy więc przesunąć warstwy lub grupy warstw w Illustratorze tak, żeby miejsca, które chcemy, żeby były środkami transformacji znalazły się w lewym górnym rogu dokumentu. Zanim to zrobimy możemy usunąć warstwy składające się na jedno z oczu sowy oraz jedno skrzydło. Zaoszczędzi nam to pracy, a te elementy zduplikujemy sobie potem w kodzie.

Przesunięcie elementów w Illustratorze
Przesunięcie elementów w Illustratorze

Na powyższym obrazku widać jak mamy przesunąć warstwy tak, aby potem miały odpowiednie środki transformacji.

Niestety nasza ilustracja nie przypomina teraz sowy. Trzeba będzie wszystkie jej części przesunięte przenieść z powrotem na swoje miejsce. Musimy je wszystkie umieścić w dodatkowych grupach (dla przejrzystości nazwijmy je wrapperami), a później, za pomocą opcji transform translate przenieść na pierwotne pozycje.

Nasze warstwy prezentują się teraz tak:

Widok warstw w Illustratorze
Widok warstw w Illustratorze

Zanim zapiszemy naszą ilustrację jako plik SVG została nam jeszcze kwestia animowanych skrzydeł. Chcę, żeby ich animacja składała się z czterech klatek, które będą się przekształcać między sobą:

  • skrzydło schowane przy ciele,
  • skrzydło w połowie ruchu w górę (wznoszące),
  • skrzydło całkowicie rozpostarte,
  • skrzydło w połowie drogi w dół (opadające).

Żeby morfowanie kształtów w SVG zadziałało, wszystkie ścieżki, które chcemy między sobą przekształcać, muszą mieć taką samą liczbę punktów kontrolnych. Mało tego – każdy z tych punktów musi być takiego samego typu (narożny, albo gładki). W Illustratorze możemy konwertować punkty używając narzędzia Zaznaczenie bezpośrednie (biała strzałka), poprzez zaznaczenie punktu na krzywej i użycie przycisku na pasku:

Konwertowanie punktów kontrolnych w Illustratorze
Konwertowanie punktów kontrolnych w Illustratorze

Aby mieć pewność, że nasze kształty bez problemu się zmorfują, polecam jednak ich duplikowanie, a potem edycję. Bierzemy więc naszą ścieżkę przedstawiającą skrzydło sowy, potem ją duplikujemy i przesuwamy jej punkty. Powtarzamy ten proces tak, aby otrzymać mniej więcej coś takiego (tak jak wcześniej różowe krzyżyki są umieszczone tylko po to, żeby zaznaczyć środki transformacji – nie umieszczamy ich w naszej ilustracji!):

Skrzydła sowy
Skrzydła sowy

Pamiętajmy, żeby przesunąć nowo utworzone warstwy na odpowiednie miejsce, czyli tak, aby ich środki transformacji znajdowały się w lewym górnym rogu dokumentu. Tak na dobrą sprawę potrzebujemy, aby widoczna była tylko jedna wersja skrzydła – ta najmniejsza, schowana. Ukrywamy więc pozostałe trzy warstwy przedstawiające kolejne klatki poprzez kliknięcie na ikonki oka obok nazwy odpowiedniej warstwy.

Jesteśmy już gotowi, aby zapisać naszą ilustrację jako plik SVG. W tym celu w menu Plik → Zapisz jako wybieramy jako format źródłowy SVG ustawiając opcje eksportu jak na poniższym obrazku.

Konwertowanie punktów kontrolnych w Illustratorze
Konwertowanie punktów kontrolnych w Illustratorze

Nie używamy opcji optymalizacji pliku, gdyż będziemy go potem edytować i musi mieć czytelną składnię.

Eksportując klikamy na przycisk Więcej opcji i w polu z ilością miejsc po przecinku wpisujemy 1. Opcja ta ogranicza ilość miejsc po przecinku dla współrzędnych punktów zmniejszając też rozmiar pliku SVG. Co prawda idzie za tym delikatne uproszczenie ścieżek, ale na potrzeby naszej ilustracji nie potrzeba większej szczegółowości, gdyż nie będzie widać różnicy.
Możemy też zaznaczyć opcję Reagujący, dzięki której nasz obrazek stanie się responsywny.

Poniżej umieszczam pliki źródłowe:

Pobierz plik AI Pobierz plik SVG

Opuszczamy teraz Illustratora i otwieramy uzyskany plik SVG w naszym ulubionym edytorze. Ja używam do tego celu Sublime text. Naszym oczom ukazuje się struktura pliku SVG, która wygląda tak:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 viewBox="0 0 600 500" style="enable-background:new 0 0 600 500;" xml:space="preserve">
<style type="text/css">
	.st0{fill:#A67F77;stroke:#4E328A;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;}
	.st1{fill:#959595;}
	.st2{fill:#D2B2A2;}
	.st3{fill:none;stroke:#4E328A;stroke-width:4;stroke-linecap:round;stroke-miterlimit:3;}
	.st4{fill:none;stroke:#4E328A;stroke-width:6;stroke-miterlimit:10;}
	.st5{fill:#FF9300;stroke:#4E328A;stroke-width:5;stroke-miterlimit:10;}
	.st6{fill:#A67F77;stroke:#4E328A;stroke-width:6;stroke-miterlimit:3;}
	.st7{fill:#4E328A;}
	.st8{fill:#FFE23F;stroke:#4E328A;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;}
	.st9{fill:#FFFFFF;}
	.st10{display:none;fill:#B69994;stroke:#645296;stroke-width:6;stroke-miterlimit:10;}
	.st11{display:none;fill:none;stroke:#2AA837;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;}
</style>
<g id="owl-wrapper">
	<g id="owl">
		<g id="body">
			<g id="wing-R-wrapper">
				<path id="wing-R-mid-back" class="st0" d="M-5.4-21.8C25.5-7.2,31-0.4,60.5,5c48,8.8,70.2-16.2,86-15.5c3.3,0.2,7,5.1,1.1,16.8
					c-5,9.8-27.1,17.8-43.5,21.8c9.9,6.4,45.1-0.1,33.9,14.4c-16.2,20.8-39,1.3-50.8-6.6c7.6,9.9,19.6,20.9,9.6,28.6
					C80.1,77.4,54.7,48,56.2,33.2C52.5,44.9,63,57.5,54,61c-14.9,5.8-20.4-9.3-16.8-27.2c0,0,1.3,10.6-9.8,11.5S17.2,29,17.2,29
					s-5,4.5-10.1,3c-6.9-2-4.6-11.5-4.6-11.5S-2,27.3-8.3,27.4c-7.9,0.1-8.7-3-9.7-9.6C-19.5,7.8-16.5-27-5.4-21.8z"/>
				<path id="wing-R-open" class="st0" d="M0.1-14.2c4.5-8.3,97.6-17.7,127.5-20.1c32.6-2.6,81.4,24.6,102,25.1
					c25.5,0.6,16,16,8.6,18.9c-13.2,5.2-44,0.7-62-8.4c14.2,13.3,55.9,19.6,47.9,29.9c-13.3,17.1-53.9-6.4-70.8-19.2
					c11.2,12.9,49.1,25.6,39.8,35.6c-13.8,14.8-57.9-14.7-72.6-22.1c9.2,7.9,23.5,17.3,15.7,22.7c-10.1,7.2-34.6-4-48.1-21.6
					c0,0,12.5,13,1.4,13.9S61.4,25.9,61.4,25.9s0.4,11.4-4.4,10.8c-7.1-0.9-20-8.6-20-8.6s0.2,6.4-6.1,6.5C23,34.7-6.4,25.2-8.7,19
					C-9.9,15.8-3.6-7.3,0.1-14.2z"/>
				<path id="wing-R-mid" class="st0" d="M-5.4-21.8c31.9,2.3,85.5-12.3,109.9,5.1c32,22.8,9.3,49,26,80.8
					c1.5,2.9-4.3,14.2-15.5,7.5c-16.5-9.9-12.2-26.2-15.5-43.2c0.1,14.5,11.3,52.8-5.1,44.8C70.6,61.6,76.2,40,79.8,27.5
					C74.2,39.4,77.7,70,68.1,65c-18.7-9.8-9-23.6-7.5-38.4c-3.7,11.7-3.5,33-12,29.3c-7.9-3.4-12.9-13.2-9.3-31.1
					c0,0-1.6,13-12.7,13.9s-9.5-13.8-9.5-13.8s-4.9,8.7-10,7.2c-6.9-2-4.6-11.5-4.6-11.5S-2,27.3-8.3,27.4c-7.9,0.1-8.7-3-9.7-9.6
					C-19.5,7.8-17.6-22.7-5.4-21.8z"/>
				<path id="wing-R-close" class="st0" d="M-17,3.8c6.8-23.4,20.6-30.1,50.5-32.5c32.6-2.6,43.7,10.5,52.1,29.2
					c4.1,9.1,3.6,20.9-4.1,23c-5.1,1.4-8.3,1.4-11.6-15.7C70,22.3,68.7,25.1,64.7,26c-5,1.1-9.2-1.4-5.6-13.9
					c-1.9,11.6-1.7,15.7-8.7,15.7c-5.2,0-9.5-1.6-8-16.4C41.5,23.5,40.1,29.2,36,29c-5.2-0.2-6-7.6-6.5-17.5c0,0,4.4,15.9-6.7,16.8
					S15,12.5,15,12.5S11.4,27.6,6.5,27c-7.1-0.9-7.1-13.3-7.1-13.3S0.3,25.9-6,26c-7.9,0.1-9-0.7-11.4-6.9
					C-18.6,15.8-19.2,11.3-17,3.8z"/>
			</g>
			<path id="body-color-a" class="st1" d="M0-121.3c46,0,83.3,17.3,83.3,69c0,38.1-21.6,69-83.3,69c-64.5,0-84.2-30.9-83.3-69
				C-81.8-107.1-45.9-121.3,0-121.3z"/>
			<path id="body-color-b" class="st2" d="M-82-42.5c0,0,10-11.1,16.9-13.4c0.3,6.3,2.7,11.1,6.5,14.7c4.6-5.4,10.9-10,18.7-13.9
				c3.4,5.6,8.1,10.9,14,15.8c7.6-4.3,15-8.7,20.1-14.2c5.5,6.7,11.1,11.1,16.7,14.9c4.7-2.1,9-4.5,12.7-7.3
				c3.6-2.6,6.7-5.5,9.2-8.7c6.6,4.1,11.6,9.3,15.3,15.3c7.2-5.5,11.9-15.3,12.8-18.6C72.9-55.5,81-41,81-41s4.6-26.9-2.6-41.5
				c-10.8-22.1-33-39-79.1-39.1c-49.9-0.2-72.1,22.5-79,44.5C-83.9-63.7-82-42.5-82-42.5z"/>
			<path id="body-divider" class="st3" d="M-81.5-42.5c0,0,5.6-10.3,16.9-13.4c0.3,6.3,2.7,11.1,6.5,14.7c3.1-6.6,12-12.3,18.7-13.9
				c1.8,2.9,11.2,13.4,14,15.8c2.3-1.3,19.1-13.1,20.1-14.2c5.5,6.7,11.1,11.1,16.7,14.9c4.1-1.9,19-12.3,21.9-16
				c6.6,4.1,11.6,9.3,15.3,15.3c8.7-5.3,12-15.8,12.8-18.6C75.7-56,81.5-41,81.5-41"/>
			<path id="body-outline" class="st4" d="M0-121.3c46,0,83.3,17.3,83.3,69c0,38.1-21.6,69-83.3,69c-64.5,0-84.2-30.9-83.3-69
				C-81.8-107.1-45.9-121.3,0-121.3z"/>
		</g>
		<g id="foot-L-wrapper">
			<path id="foot-L" class="st5" d="M-10.9,11.3C-28.5,1.5-26.7-22-18.5-25.6c5.4-2.3,9.8,5.4,9.8,5.4s0.1-11.7,9-12
				c8.9-0.4,8.8,8.8,8.8,8.8S13.7-33.6,20-31c6.4,2.6,4.4,14.8,3.3,19.8c-1.1,4.9-2.1,10.1-1.9,20C12.7,4.3,8.8-3.7,8.8-3.7
				S5.1,5.2,5.2,17.2C-3.3,8.4-7.3,0.4-7.3,0.4S-9.8,2.9-10.9,11.3z"/>
		</g>
		<g id="foot-R-wrapper">
			<path id="foot-R_1_" class="st5" d="M7.8,0.9c0,0-4.8,16.6-12.5,16.8C-4.6,5.7-8.3-1-8.3-1s-7.5,13.2-12.6,10.3
				c0.3-7.8-2-14.9-3.1-19.8s-1.9-15.5,4.5-18.1c6.3-2.5,10.9,5.8,10.9,5.8s-0.1-9.2,8.8-8.8c8.9,0.3,11,10.2,11,10.2
				s1.7-4.5,7.1-2.2c8.3,3.5,9.3,22-1.7,34.2C13.9,2.3,7.8,0.9,7.8,0.9z"/>
		</g>
		<g id="head">
			<path id="head-base" class="st6" d="M-3.8-63.9c47.1-0.4,89.6,21.4,90.7,61.7c0.8,30.5-9.9,30.5-9.2,42.5
				c1.6,2.5,15.6,12.4,11.5,25.3c-11.4-8.9-22.6-13-22.6-13s1.2,13.1-3.5,20c-8.8-10-21.9-13.8-21.9-13.8s-2,9.4-4.6,14.9
				c-4.5,0.4-22.2-12.3-22.2-12.3s-8.8,10.9-13.5,15c-5.6-3.2-14.8-16.6-14.8-16.6s-10.2,7.9-16,17.4c-8.6-3.7-18-18.3-18-18.3
				s-9.6,5.7-14.5,13.7c-8-5.3-10.4-16.1-10.4-16.1s-7.8,1.6-17,9.1c-1.8-13,11.2-15.5,11.5-24.4c0.4-11-10-13.6-9.4-42.3
				C-87-35-49.5-63.5-3.8-63.9z"/>
			<path id="forehead-line-b" class="st7" d="M2.7-22.9C1.3-28,1.1-32.5,4.4-38.2c3.3-5.6,8.4-4.6,8.4-4.6S5.5-35.3,2.7-22.9z"/>
			<path id="firehead-line-a" class="st7" d="M-2.3-17.9c-0.2-7-0.8-10.4-4.3-15.3c-4-5.7-10.8-4.8-10.8-4.8S-7.7-30.6-2.3-17.9z"/>
			<path id="line-b_1_" class="st7" d="M14.8,25.2c-2.5,3.3,2.3,11.3,10.8,17.8s17.5,9,20,5.7c-4.4-1.7-10.7-5.2-16.8-9.9
				S17.7,28.9,14.8,25.2z"/>
			<path id="line-a" class="st7" d="M-48.1,44.7c1.9,3.8,10.5,3.3,19.2-1.1s14.4-10.9,12.5-14.7c-3.1,3-8.5,6.8-14.9,9.9
				C-37.5,42-43.8,44-48.1,44.7z"/>
			<g id="eyebrow-R-wrapper">
				<g id="eye-L-wrapper">
					<g id="eye-L">
						<circle id="eye-L-base" class="st8" cx="0" cy="0" r="34"/>
						<g id="pupil-L">
							<circle id="pupil-L-base" class="st7" cx="0" cy="0" r="20.6"/>
							<circle id="blik-L-a" class="st9" cx="-3.4" cy="-6.1" r="10"/>
							<path id="blik-L-b" class="st9" d="M-1.9,11.5c0.2,1.2,5.4,4.2,11.2,1.5c2.3-1.1,3.6-3.8,2.4-5.4c-1.1-1.6-3.5-2.1-5-1
								C3.8,8.7,2.4,10.8-1.9,11.5z"/>
						</g>
						<circle id="eyelid-L" class="st10" cx="0" cy="0" r="34"/>
					</g>
				</g>
				<path id="eyebrow-R" class="st7" d="M3.9,5.8c0,0-4.3-25.1,19.9-38.3c11-6,25.9-3,41.3-16.4c27.4-24,29.9-48.6,30.7-58.3
					c13,20.8-3,47.9-5.9,50.5c14.7-6.6,21.8,1.1,25,7.8C96.3-53,88.7-30.2,71.7-19.8C55.7-10,48.1-22,24.2-10
					C13.9-4.8,3.9,5.8,3.9,5.8z"/>
			</g>
			<g id="eyebrow-L-wrapper">
				<path id="eyebrow-L" class="st7" d="M-3.5,4.6c0,0,4.5-28.1-24.7-39.5C-41.5-40-40.5-37.3-51-46.2c-18.2-15.6-22.1-29-22.3-35.1
					c-5.1,6.2-9.5,18-8.9,19.7C-94-69-97.8-79.8-107.5-89.1s-14.6-13.1-19.2-14c8.2,7.3,10.1,15.9,14.1,23.5
					c4.3,7.9,7.5,15.5,10,18.5c-2.9,2.5-14.5-1-14.5-1s12.3,17.8,35.8,35.5c14.8,11.2,45.8,13.1,51.8,14.4
					C-10.7-8.1-3.5,4.6-3.5,4.6z"/>
			</g>
			<path id="beak" class="st5" d="M0,1.8l14.3,26.3L0,49.5L-14.3,28L0,1.8z"/>
		</g>
	</g>
</g>
<path id="motionpath" class="st11" d="M-0.6-0.3C1.6-4,7.2-11.1,14.6-11.5c7.4-0.4,12.9,5.3,13.3,11C28.3,5.1,22.9,9,15.1,9
	C11.4,9,4.5,4.3-0.6-0.3c-6-5.4-10.9-10.1-16.6-9.9c-10.6,0.4-12.7,5.9-12.9,9.9c-0.2,3.9,5.3,10.7,12.5,10.7
	C-10.1,10.5-3,3.8-0.6-0.3z"/>
</svg>

Jak widać przypomina nieco strukturę pliku HTML. W elemencie style znajdują się wszystkie style CSS – tutaj będziemy dodawać nasze reguły.

Element g, to grupa, path oznacza ścieżkę, której parametr d zawiera wszystkie jej punkty, natomiast circle, to nic innego jak okrąg, którego środek ma współrzędne cxcy, a jego promień opisuje parametr r. Trzeba zauważyć też, że kolejność warstw jest odwrotna niż ta w Illustratorze – tam im warstwa była wyżej na liście, tym rysowana była wyżej od innych warstw. W SVG kolejność jest odwrotna – wcześniej opisane elementy są rysowane pierwsze, podobnie jak w języku HTML.

Teraz zajmiemy się przeniesieniem na swoje miejsce elementów sowy, którym wcześniej ustawiliśmy środki transformacji. Użyjemy do tego celu opcji transform = translate(x, y), gdzie x, to przesunięcie w prawo, a y – w dół.
Dodajemy transformacje następująco:

<g id="owl-wrapper" transform="translate(300, 300)">
<g id="wing-R-wrapper" transform="translate(70, -80)">
<g id="foot-L-wrapper" transform="translate(-35, 20)">
<g id="foot-R-wrapper" transform="translate(35, 20)">
<g id="head" transform="translate(0, -150)">
<g id="eye-L-wrapper" transform="translate(-40, 0)">

Otrzymujemy taki widok:

owl_09

Jak widać wszystkie elementy są na swoim miejscu. Brakuje tylko prawego oka oraz lewego skrzydła. Przydałoby się też, żeby skrzydło było obrócone w kierunku korpusu sowy.

W SVG możemy łatwo zduplikować jakiś element, albo grupę elementów używając elementu use. Zróbmy to na przykładzie oka: zaraz po tagu zamykającym grupę o id="eye-L-wrapper" dodajemy:

<use xlink:href="#eye-L-wrapper" transform="translate(80, 0)" />

Otrzymujemy wtedy:

...
<g id="eye-L-wrapper" transform="translate(-40, 0)">
	<g id="eye-L">
		<circle id="eye-L-base" class="st9" cx="0" cy="0" r="34"/>
		<g id="pupil-L">
			<circle id="pupil-L-base" class="st8" cx="0" cy="0" r="20.6"/>
			<circle id="blik-L-a" class="st10" cx="-3.4" cy="-6.1" r="10"/>
			<path id="blik-L-b" class="st10" d="M-1.9,11.5c0.2,1.2,5.4,4.2,11.2,1.5c2.3-1.1,3.6-3.8,2.4-5.4c-1.1-1.6-3.5-2.1-5-1
				C3.8,8.7,2.4,10.8-1.9,11.5z"/>
		</g>
		<circle id="eyelid-L" class="st11" cx="0" cy="0" r="34"/>
	</g>
</g>
<use xlink:href="#eye-L-wrapper" transform="translate(80, 0)" />
...

Dodajemy też drugie skrzydło jednocześnie obracając je poleceniem transform="rotate(90)". Możemy także zakomentować skrzydła o id wing-R-mid-back, wing-R-open, wing-R-mid. Nie będą one nam na razie potrzebne.

Kod obydwu skrzydeł wyglądał będzie teraz tak:

...
<g id="wing-R-wrapper" transform="translate(70, -80)">
	<!-- <path id="wing-R-mid-back" class="st0" d="M-5.4-21.8C25.5-7.2,31-0.4,60.5,5c48,8.8,70.2-16.2,86-15.5c3.3,0.2,7,5.1,1.1,16.8
		c-5,9.8-27.1,17.8-43.5,21.8c9.9,6.4,45.1-0.1,33.9,14.4c-16.2,20.8-39,1.3-50.8-6.6c7.6,9.9,19.6,20.9,9.6,28.6
		C80.1,77.4,54.7,48,56.2,33.2C52.5,44.9,63,57.5,54,61c-14.9,5.8-20.4-9.3-16.8-27.2c0,0,1.3,10.6-9.8,11.5S17.2,29,17.2,29
		s-5,4.5-10.1,3c-6.9-2-4.6-11.5-4.6-11.5S-2,27.3-8.3,27.4c-7.9,0.1-8.7-3-9.7-9.6C-19.5,7.8-16.5-27-5.4-21.8z"/>
	<path id="wing-R-open" class="st0" d="M0.1-14.2c4.5-8.3,97.6-17.7,127.5-20.1c32.6-2.6,81.4,24.6,102,25.1
		c25.5,0.6,16,16,8.6,18.9c-13.2,5.2-44,0.7-62-8.4c14.2,13.3,55.9,19.6,47.9,29.9c-13.3,17.1-53.9-6.4-70.8-19.2
		c11.2,12.9,49.1,25.6,39.8,35.6c-13.8,14.8-57.9-14.7-72.6-22.1c9.2,7.9,23.5,17.3,15.7,22.7c-10.1,7.2-34.6-4-48.1-21.6
		c0,0,12.5,13,1.4,13.9S61.4,25.9,61.4,25.9s0.4,11.4-4.4,10.8c-7.1-0.9-20-8.6-20-8.6s0.2,6.4-6.1,6.5C23,34.7-6.4,25.2-8.7,19
		C-9.9,15.8-3.6-7.3,0.1-14.2z"/>
	<path id="wing-R-mid" class="st0" d="M-5.4-21.8c31.9,2.3,85.5-12.3,109.9,5.1c32,22.8,9.3,49,26,80.8
		c1.5,2.9-4.3,14.2-15.5,7.5c-16.5-9.9-12.2-26.2-15.5-43.2c0.1,14.5,11.3,52.8-5.1,44.8C70.6,61.6,76.2,40,79.8,27.5
		C74.2,39.4,77.7,70,68.1,65c-18.7-9.8-9-23.6-7.5-38.4c-3.7,11.7-3.5,33-12,29.3c-7.9-3.4-12.9-13.2-9.3-31.1
		c0,0-1.6,13-12.7,13.9s-9.5-13.8-9.5-13.8s-4.9,8.7-10,7.2c-6.9-2-4.6-11.5-4.6-11.5S-2,27.3-8.3,27.4c-7.9,0.1-8.7-3-9.7-9.6
		C-19.5,7.8-17.6-22.7-5.4-21.8z"/> -->
	<path id="wing-R" transform="rotate(90)" class="st1" d="M-17,3.8c6.8-23.4,20.6-30.1,50.5-32.5c32.6-2.6,43.7,10.5,52.1,29.2c4.1,9.1,3.6,20.9-4.1,23
		c-5.1,1.4-8.3,1.4-11.6-15.7C70,22.3,68.7,25.1,64.7,26c-5,1.1-9.2-1.4-5.6-13.9c-1.9,11.6-1.7,15.7-8.7,15.7
		c-5.2,0-9.5-1.6-8-16.4C41.5,23.5,40.1,29.2,36,29c-5.2-0.2-6-7.6-6.5-17.5c0,0,4.4,15.9-6.7,16.8S15,12.5,15,12.5
		S11.4,27.6,6.5,27c-7.1-0.9-7.1-13.3-7.1-13.3S0.3,25.9-6,26c-7.9,0.1-9-0.7-11.4-6.9C-18.6,15.8-19.2,11.3-17,3.8z"/>
</g>
<use xlink:href="#wing-R-wrapper" transform="scale(-1, 1)" />
...

Nasza ilustracja sowy jest już gotowa do animacji i prezentuje się tak:

owl_10

Jest kilka sposobów animowania elementów SVG. Skoro format ten integruje się ładnie z HTMLem, to warto to wykorzystać.

Animacje CSS

Jedną z zalet formatu SVG jest obsługa animacji CSS – zarówno osadzonych wewnątrz pliku SVG jak tych umieszczonych w zewnętrznym arkuszu stylów. Taki sposób ma też swoje ograniczenia – w zależności w jaki sposób umieścimy nasz obraz SVG na stronie. Dla zachowania jak największej kompatybilności wszystkie style CSS będziemy jednak umieszczać wewnątrz elementu style w naszym pliku SVG.

Zaczynamy od animacji źrenic sowy. Tworzymy najpierw samą animację i jej klatki kluczowe.

...
<style>
...
	@keyframes eyes_roll{
		0%{
			transform: translateX(0px);
		}
		5%{
			transform: translateY(-8px);
		}
		15%{
			transform: translateY(-8px);
		}
		20%{
			transform: translateX(16px);
		}
		40%{
			transform: translateX(16px);
		}
		45%{
			transform: translateX(-16px);
		}
		65%{
			transform: translateX(-16px);
		}
		70%{
			transform: translateY(16px);
		}
		75%{
			transform: translateY(16px);
		}
		80%{
			transform: translateX(0px);
		}
		100%{
			transform: translateX(0px);
		}
	}
</style>
...

Teraz przypisujemy animację do źrenicy.

#pupil-L {
    animation: eyes_roll 8s 6s ease both infinite;
}

Aby animacja była bardziej wiarygodna przydałoby się zanimować także brwi. Do tego celu potrzebujemy dwóch oddzielnych animacji – dla lewej i prawej brwi. Animacje muszą być zsynchronizowane z ruchem źrenic. Przypisujemy odpowiednie animacje do grup – wrapperów, w których znajdują się grafiki brwi.

    @keyframes eyebrowl_l_roll{
        0%{
            transform: translateX(0px) rotate(0);
        }
        5%{
            transform: translateY(-4px) rotate(5deg);
        }
        15%{
            transform: translateY(-4px) rotate(5deg);
        }
        20%{
            transform: translateX(0px) rotate(-5deg);
        }
        40%{
            transform: translateX(0px) rotate(-5deg);
        }
        45%{
            transform: translateX(0) rotate(5deg);
        }
        65%{
            transform: translateX(0) rotate(5deg);
        }
        70%{
            transform: translateY(0) rotate(-10deg);
        }
        75%{
            transform: translateY(0) rotate(-10deg);
        }
        80%{
            transform: translateX(0px) rotate(0);
        }
        100%{
            transform: translateX(0px) rotate(0);
        }

    }

@keyframes eyebrowl_r_roll{
    0%{
        transform: translateX(0px) rotate(0);
    }
    5%{
        transform: translateY(-4px) rotate(-5deg);
    }
    15%{
        transform: translateY(-4px) rotate(-5deg);
    }
    20%{
        transform: translateX(0px) rotate(-5deg);
    }
    40%{
        transform: translateX(0px) rotate(-5deg);
    }
    45%{
        transform: translateX(0) rotate(5deg);
    }
    65%{
        transform: translateX(0) rotate(5deg);
    }
    70%{
        transform: translateY(0) rotate(10deg);
    }
    75%{
        transform: translateY(0) rotate(10deg);
    }
    80%{
        transform: translateX(0px) rotate(0);
    }
    100%{
        transform: translateX(0px) rotate(0);
    }

}

#eyebrow-L-wrapper{
    animation: eyebrowl_l_roll 8s 6s ease both infinite;
    transform-origin: -10px -20px;
}

#eyebrow-R-wrapper{
    animation: eyebrowl_r_roll 8s 6s ease both infinite;
    transform-origin: 10px -20px;
}

Użyłem też atrybutu transfrom-origin, aby przesunąć lekko środki obrotu brwi by lepiej pasowały do oczu.

Sprawimy teraz aby po otwarciu obrazka sowa znajdowała się powyżej górnej krawędzi i po chwili lądowała na środku.

    @keyframes land {
        0% {

            transform: translateY(-1000px);
        }

        70% {

            transform: translateY(-30px);
        }

        90% {
            transform: translateY(-50px);
        }

        95% {
            transform: translateY(0) scale(1.2, 0.8);
        }

        100% {
            transform: translateY(0) scale(1, 1);
        }
    }

    #owl{
        animation: land 5s 0s ease both;

Dodamy też lekką animację szponów sowy przy lądowaniu.

    @keyframes land-feet {
        from {

            transform: translateY(0px);
        }

        60%, 95% {

            transform: translateY(15px);
        }

        98% {
            transform: translateY(-10px);
        }

        to {
            transform: translateY(0);
        }
    }

    #foot-L{
        animation: land-feet 5s 0s ease both;
    }

    #foot-R{
        animation: land-feet 5s 0.05s ease both;
    }

Po dodaniu wszystkich animacji CSS, sowa nabrała trochę życia:

owl_anim_02
Wizualizacja animacji w formacie GIF

Nadal brakuje jeszcze animacja machania skrzydłami podczas lądowania. Tego niestety nie będziemy mogli zrobić animacjami CSS, więc wykorzystamy…

Animacje SMIL

SMIL, jest składnią językową stosowaną w XMLu do prezentacji multimedialnych. Dzięki niemu możemy animować elementy plików SVG.
Do zanimowania naszej sowy użyjemy trzech typów animacji:

  • pozwala na animowanie transformacji obiektu takich jak przesunięcie, obrót, skalowanie oraz pochylenie
  • pozwala na animowanie dowolnego atrybutu elementu. Dzięki niemu możemy np. morfować kształty
  • pozwala na przesuwanie elementu po ścieżce

Chcąc użyć tych animacji możemy zrobić to na dwa sposoby.

Pierwszy, to umieszczenie animacji wewnątrz elementu, np.:

<g>
	<animate  ...tutaj są atrybuty animacji... />
</g>

<path ...tutaj są atrybuty ścieżki...>
	<animatTransform  ...tutaj są atrybuty animacji... />
</path>

<circle ...tutaj są atrybuty elipsy...>
	<animate  ...tutaj są atrybuty animacji... />
</circle>

Albo odnosić się do elementu używając jego id w atrybucie xlink

<circle id="eyelid-L" cx="0" cy="0" r="34">
<animateTransform id="rotate" xlink:href="#eyelid-L" attributeType="xml"
	attributeName="transform"
	begin="1s"
	type="rotate"
	values="0; 180; 0"
	dur="1s"
	repeatCount="2"/>

W tym wypadku nie ma znaczenia, w której linii w pliku SVG znajduje się element zawierający animację, więc możemy umieścić wszystkie animacje w jednym miejscu np. na samym dole.

Wracamy jednak do animacji ruchu skrzydeł sowy. Będzie wyglądała ona tak:

<animateTransform id="wing-rotate" attributeType="xml"
						attributeName="transform"
						type="rotate"
						begin="0"
						values="90; -60; 90"
						dur="1s"
						keyTimes="0; 0.7; 1"
						repeatCount="5"/>

Wyjaśnię teraz co oznaczają wszystkie atrybuty.

  • id="wing-rotate" – nazwa animacji;
  • attributeType="xml" – typ animacji. Oprócz wartości xml czyli wartości domyślnej możemy wpisać też wartość css, co pozwoli nam na animowanie atrybutów css zupełnie jakbyśmy używali animacji css. Użyjemy tej opcji w dalszej części;
  • attributeName="transform" – oznacza, że będziemy modyfikować transformację obiektu;
  • type="rotate" – oznacza typ transformacji, w tym wypadku obrót;
  • begin="0" – czas (lub warunek – więcej o tym później) rozpoczęcia animacji, wartość 0 oznacza natychmiastowe rozpoczęcie;
  • values="90; -60; 90" – wartości kluczowe naszej animacji oddzielone średnikiem. Tutaj skrzydło rozpocznie obrócone o 90 stopni, uniesie się do góry 60 stopni w przeciwną stronę jego domyślnego położenia i wróci do obrotu o 90 stopni;
  • dur="1s" – długość trwania animacji;
  • keyTimes="0; 0.7; 1" – położenie w czasie poszczególnych wartości kluczowych animacji. Każdą z tych wartości mnożymy przez czas trwania animacji i otrzymujemy czas, w którym zostanie zmieniona odpowiednia wartość kluczowa animacji. W naszym wypadku dla 1 sekundy będzie to tak: 0 sekund – obrót do 90 stopni, 0.7 sekundy – obrót do -60 stopni, 1 sekunda – powrót do 90 stopni i koniec animacji. Ilość liczb w tym atrybucie musi się zgadzać z ilością wartości kluczowych w polu values – czyli u nas jest to trzy;
  • repeatCount="5" – ilość powtórzeń animacji. Jeśli chcemy, żeby animacja zapętlała się w nieskończoność wpisujemy wartość `indefinite`;

Animację tę umieszczamy wewnątrz elementu path naszego skrzydła w taki sposób:

<path id="wing-R" transform="rotate(90)" class="st1" d="...punkty krzywej...">
    <animateTransform id="wing-rotate" attributeType="xml"
        attributeName="transform"
        type="rotate"
        begin="0"
        values="90; -60; 90"
        dur="1s"
        keyTimes="0;0.7;1"
        repeatCount="5"/>
</path>

Sowa już macha skrzydłami przy lądowaniu, ale ich jeszcze nie rozpościera. Musimy więc zmorfować ścieżkę opisującą skrzydło w pozostałe wersje, które przygotowaliśmy wcześniej w Illustratorze. Jeśli wszystko narysowaliśmy wcześniej poprawnie kod animacji będzie bardzo prosty i będzie wyglądał tak:

<animate id="winganim"
    attributeName="d"
    begin="0"
    dur="1s"
    keyTimes="0;0.4;0.7;0.8;1"
    repeatCount="5"
    values=""
    />

Będziemy tutaj jak widać animować atrybut o nazwie d czyli punkty ścieżki. Jak na razie pole wartości values jest puste, musimy je uzupełnić kopiując wartości atrybutu d z czterech ścieżek będących skrzydłami sowy. Dla przypomnienia mają one następujące id: wing-R, wing-R-mid, wing-R-open oraz wing-R-mid-back. Pamiętamy by oddzielić je od siebie średnikiem.

values="tutaj wklejamy współrzędne ścieżki wing-R;
        tutaj wklejamy współrzędne ścieżki wing-R-mid;
        tutaj wklejamy współrzędne ścieżki wing-R-open;
        tutaj wklejamy współrzędne ścieżki wing-R-mid-back;
        tutaj wklejamy współrzewspółrzędnedne ścieżki wing-R"
Wizualizacja animacji w GIF
Wizualizacja animacji formacie w GIF

Jeśli między różnymi wersjami ścieżki przejście nie jest płynne i zachodzi tylko podmiana grafiki, trzeba wrócić do Illustratora i jeszcze raz sprawdzić, czy każda z wersji skrzydła składa się z tej samem liczby punktów i czy są one tego samego typu (ostre lub gładkie).

Dodajmy jeszcze animację mrugania oczami. W tym celu wykorzystamy kilka animacji.
Pierwsza z nich to animacja skalowania oka. Umieścimy ją w grupie o id eye-L.

<g id="eye-L">
    <circle id="eye-L-base" class="st9" cx="0" cy="0" r="34"/>
    <g id="pupil-L">
        <circle id="pupil-L-base" class="st8" cx="0" cy="0" r="20.6"/>
        <circle id="blik-L-a" class="st10" cx="-3.4" cy="-6.1" r="10"/>
        <path id="blik-L-b" class="st10" d="M-1.9,11.5c0.2,1.2,5.4,4.2,11.2,1.5c2.3-1.1,3.6-3.8,2.4-5.4c-1.1-1.6-3.5-2.1-5-1
            C3.8,8.7,2.4,10.8-1.9,11.5z"/>
    </g>
    <circle id="eyelid-L" class="st11" cx="0" cy="0" r="34"/>
    <animateTransform id="blink" attributeType="xml"
        attributeName="transform"
        type="scale"
        values="1,1; 1,1; 1,0.3; 1,1"
        dur="4s"
        keyTimes="0;0.98;0.99;1"
        repeatCount="indefinite"/>
</g>

Kolejna animacja sprawi, że powieka na chwilę się pojawi, sprawiając wrażenie zamykania. Umieścimy ją w elemencie circle o id eyelid-L.

<circle id="eyelid-L" class="st11" cx="0" cy="0" r="34">
    <animate id="blink-eyelid" attributeType="css"
    attributeName="opacity"
    values="0; 0; 1; 1"
    dur="4s"
    keyTimes="0;0.96;0.97;1"
    repeatCount="indefinite"/>
</circle>

Zauważmy, że użyłem attributeType="css". Oznacza to, że animacja odnosi się do trybutu opacity języka CSS, a nie SMIL. Żeby zadziałała musimy zmodyfikować klasę st11, której używa element tworzący powiekę.

.st11{display:none;fill:#B69994;stroke:#645296;stroke-width:6;stroke-miterlimit:10;}

Zamieniamy więc na:

.st11{opacity:0;fill:#B69994;stroke:#645296;stroke-width:6;stroke-miterlimit:10;}

Oczy już mrugają, ale brwi pozostają na miejscu. Łatwo temu zaradzimy dodając te dwie animacje na końcu pliku SVG, ale przed zamykającym tagiem.

<animateTransform id="blink-eyebrow-L" xlink:href="#eyebrow-L" attributeType="xml"
    attributeName="transform"
    type="translate"
    values="0,0; 0,0; 0,10; 0,0"
    dur="4s"
    keyTimes="0;0.98;0.99;1"
    repeatCount="indefinite"/>

<animateTransform id="blink-eyebrow-R" xlink:href="#eyebrow-R" attributeType="xml"
    attributeName="transform"
    type="translate"
    values="0,0; 0,0; 0,10; 0,0"
    dur="4s"
    keyTimes="0;0.98;0.99;1"
    repeatCount="indefinite"/>

Po tych operacjach ilustracja prezentuje się tak:

owl_anim_04
Wizualizacja animacji w formacie GIF

Moglibyśmy ją już tak zostawić, ale dodajmy jeszcze parę smaczków. Skoro mamy animację machania skrzydłami, to możemy ją wykorzystać powtórnie i odtwarzać po kliknięciu na brzuch sowy. Ta dodatkowa opcja wymaga od nas lekkiej modyfikacji animacji winganim, którą zmieniamy na:

<animate id="winganim" 
    attributeName="d"  
    begin="0;body.click"
    dur="1s"
    keyTimes="0;0.4;0.7;0.8;1"
    repeatCount="5"
    values="...tutaj znajdują się wartości animacji..."/>

Jak widać jedyne co się zmieniło to linia begin="0;body.click". Dodaliśmy dodatkową wartość po średniku, która oznacza, że animacja będzie odgrywana po kliknięciu w element o id body. Musimy także zastosować zmianę do animacji obracania skrzydeł.

<animateTransform id="wing-rotate" attributeType="xml"
    attributeName="transform"
    type="rotate"
    begin="winganim.begin"
    values="90; -60; 90"
    dur="1s"
    keyTimes="0;0.7;1"
    repeatCount="5"/>

Tutaj wpisujemy w polu begin wartość winganim.begin. Sprawi to, że nasza animacja będzie odgrywana za każdym razem, gdy inna animacja o id winganim się rozpocznie.

Na koniec sprawmy jeszcze, żeby po kliknięciu na głowę sowy, kiwała nią na lewo i prawo po ścieżce. Będziemy do tego celu potrzebować nowej krzywej stworzonej w Illustratorze. Otwieramy więc z powrotem ten program i używając narzędzia Pióro tworzymy nową krzywą wyglądającą jak obrócona o 90 stopni ósemka lub jak kto woli, symbol nieskończoności. Pamiętajmy, że początek tej krzywej musi znajdować się w lewym górnym rogu dokumentu. Nazywamy naszą warstwę motionpath.

Krzywa po której będzie poruszała się głowa sowy
Krzywa po której będzie poruszała się głowa sowy

Gdy już krzywa będzie gotowa i wyglądała jak powyżej kopiujemy jej kod – najprościej w oknie zapisu pliku do SVG klikając na przycisk Kod SVG…. Po jego kliknięciu ukaże się okno edytora tekstowego z naszym kodem. Kopiujemy interesującą nas część, która wygląda mniej więcej tak:

<path id="motionpath" class="st12" d="M-0.6-0.3C1.6-4,7.2-11.1,14.6-11.5c7.4-0.4,12.9,5.3,13.3,11C28.3,5.1,22.9,9,15.1,9C11.4,9,4.5,4.3-0.6-0.3c-6-5.4-10.9-10.1-16.6-9.9c-10.6,0.4-12.7,5.9-12.9,9.9c-0.2,3.9,5.3,10.7,12.5,10.7C-10.1,10.5-3,3.8-0.6-0.3z"/>

Zostawiamy Illustratora i przechodzimy do edycji naszego głównego pliku SVG. Musimy stworzyć w nim element defs. Służy on do przechowywania elementów, do których chcemy się odnieść później, a które nie są wyświetlane i nie zaśmiecają nam naszej ilustracji. Może zawierać też takie rzeczy jak patterny, gradienty bądź też filtry. Po tagu </style> wpisujemy więc <defs></defs> i wklejamy w środek wcześniej skopiowaną ścieżkę. Będzie to wyglądać tak:

...
</style>
<defs>
    <path id="motionpath" class="st12" d="M-0.6-0.3C1.6-4,7.2-11.1,14.6-11.5c7.4-0.4,12.9,5.3,13.3,11C28.3,5.1,22.9,9,15.1,9
    C11.4,9,4.5,4.3-0.6-0.3c-6-5.4-10.9-10.1-16.6-9.9c-10.6,0.4-12.7,5.9-12.9,9.9c-0.2,3.9,5.3,10.7,12.5,10.7
    C-10.1,10.5-3,3.8-0.6-0.3z"/>
</defs>
<g id="owl-wrapper" transform="translate(300, 300)">
...

Teraz jesteśmy gotowi do stworzenia animacji ruchu głowy po ścieżce.

<animateMotion id="headbob" xlink:href="#head" dur="1s" begin="click" fill="freeze" repeatCount="2">
    <mpath xlink:href="#motionpath" />
</animateMotion>

Użyliśmy do tego celu wspomnianego wcześniej elementu animateMotion pozwalającego na ruch po ścieżce. Ścieżkę, po której ma się poruszać głowa wyznaczona atrybutem xlink:href="#head" opisuje element mpath – w naszym wypadku ma ona id motionpath.

Oprócz ruchu głowy musimy dodać też animację tułowia. Zrobimy to prostym pochyleniem w osi X.

<animateTransform id="bodySkew" xlink:href="#body" attributeType="xml"
    attributeName="transform"
    begin="headbob.begin"
    additive="sum"
    type="skewX"
    values="0; -10; 0; 10; 0"
    dur="1s"
    repeatCount="2"/>

Obie animacje dodajemy na końcu naszego pliku SVG. Oto rezultat końcowy:

Wizualizacja animacji w formacie GIF
Wizualizacja animacji w formacie GIF

Jeśli chcesz zobaczyć jak animacja prezentuje się w formacie SVG – zerknij tutaj. Warto też zauważyć, że wersja w formacie GIF waży 837 KiB, a SVG jedynie 15. To gigantyczna oszczędność, szczególnie biorąc pod uwagę to, że SVG wygląda zdecydowanie lepiej, działa płynnie i można ją skalować bez utraty na jakości.

Jeśli chcemy umieścić naszą ilustrację na stronie i zachować pełną funkcjonalność (łącznie z interaktywnością), to musimy użyć poniższych metod.

Object

W praktyce najlepsza opcja do osadzania plików SVG.

<object type="image/svg+xml" data="owl.svg">
    <img src="owl.png" alt="ilustracja sowy" />
    Twoja przeglądarka nie obsługuje plików SVG!
</object>

Iframe

<iframe src="owl.svg">
    <img src="owl.png" alt="ilustracja sowy" />
</iframe>

Embed

<embed type="image/svg+xml" src="owl.svg" />

Osadzenie w HTML

Możemy po prostu skopiować całą zawartość kodu z pliku SVG i umieścić bezpośrednio w kodzie HTML. Daje to najłatwiejszy dostęp do zawartości SVG i np. jego stylowanie, ale może być kłopotliwe w przypadku długiego kodu.

Podsumowanie

Przedstawiłem tutaj jak najwięcej technik animacji pliku SVG, choć daleko jeszcze do wyczerpania tematu. Jak widzimy jest to bardzo potężny format w pełni mogący zastąpić flasha, a nawet w pewnych aspektach go przewyższający. Do zalet na pewno należy fakt, iż SVG jest formatem wektorowym, mogącym się łatwo skalować do dowolnych rozmiarów. Ponadto na plus wypada mała waga pliku – nasza sowa ma rozmiar około 15kb i to przed optymalizacją! Z drugiej strony jest jeszcze parę zgrzytów jeśli chodzi o obsługę przez przeglądarki, jednak myślę iż format będzie się dalej rozwijał i zyskiwał na popularności, a co za tym idzie stanie się nieodzownym elementem każdej strony. Warto się więc z nim zapoznać już teraz, żeby być na bieżąco ze zmianami w branży.

To może Cię zainteresować