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
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.
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…
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.
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.
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:
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:
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!):
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.
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 cx
i cy
, 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:
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:
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:
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 poluvalues
– 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"
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:
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
.
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:
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.