SMIL, CSS, JavaScript — i jak wybrać, nie żałując potem
SVG można animować na trzy niezależne sposoby. Nie są to warianty tego samego mechanizmu ani kolejne wersje tej samej technologii — to trzy osobne systemy, o różnych mocnych stronach i różnych ograniczeniach.
Nie ma wśród nich jednego słusznego. Jest za to dość prosta reguła wyboru i do niej dojdziemy na końcu.
Droga pierwsza: SMIL
Animacja zapisana wewnątrz samego pliku SVG, w postaci znaczników.
html
<circle cx="40" cy="40" r="16" fill="#e05c1a">
<animate attributeName="cx"
values="40; 200; 40"
dur="2.5s"
repeatCount="indefinite"/>
</circle>
Element <animate> siedzi w środku kształtu, który animuje. Mówi, który atrybut zmieniać, jakie wartości po kolei przyjmować i jak długo ma to trwać.
Do przekształceń służy osobny znacznik <animateTransform>, bo transform nie jest zwykłym atrybutem tekstowym — trzeba podać jeszcze type, czyli o jaki rodzaj przekształcenia chodzi.
Obie animacje działają w podglądzie na żywo, bez ani jednej linijki CSS i bez skryptu. Ustaw obie długości na tę samą wartość, a ruchy się zsynchronizują.
Największa zaleta SMIL: plik jest samowystarczalny. Animacja działa nawet wtedy, gdy SVG jest wstawiony przez <img src="ikona.svg">, ustawiony jako background-image albo otwarty bezpośrednio jako plik. Żadna inna metoda tego nie potrafi — o czym za chwilę.
Trzeba jednak wspomnieć o pewnym epizodzie, bo do dziś krąży w internecie i budzi niepotrzebny lęk. Dziesięć lat temu Chrome ogłosił zamiar wycofania SMIL, a potem wycofał się z tego zamiaru. Wsparcie zostało i dziś działa we wszystkich aktualnych przeglądarkach. Nadal jednak trafisz na artykuły i odpowiedzi na forach napisane w tamtym okresie, które odradzają SMIL jako „przestarzały". Warto wiedzieć, skąd to się bierze.
Droga druga: CSS
Ta sama robota, ale w składni, którą znasz z reszty frontendu.
html
<style>
.puls-demo {
animation: puls-demo 2s ease-in-out infinite;
transform-origin: 120px 65px;
}
@keyframes puls-demo {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.4); opacity: .4; }
}
</style>
Znacznik
<style>może siedzieć wewnątrz SVG, dokładnie tak jak tutaj. Zwykle jednak wygodniej trzymać te reguły w arkuszu strony.
Zalety są oczywiste: znane funkcje czasowe, :hover, zapytania medialne, transition do prostych przejść i możliwość sterowania wszystkim przez zmianę klasy.
Ograniczenia są mniej oczywiste, ale ważne. CSS działa tylko wtedy, gdy SVG jest wstawiony inline — jako <svg> w kodzie strony albo z regułami wewnątrz pliku. Grafika osadzona przez <img> jest dla arkusza stylów strony czarną skrzynką i żadna reguła do niej nie dotrze. Wrócimy do tego w osobnej lekcji, bo to jedno z najczęstszych źródeł frustracji.
Druga rzecz: nie każdy atrybut SVG jest właściwością CSS. cx, cy, r, opacity i fill animować można. Atrybut d ścieżki — w części przeglądarek tak, w części nie. Atrybutów w rodzaju points czy viewBox nie ruszysz w ogóle. SMIL nie ma tego ograniczenia, bo działa na atrybutach, a nie na właściwościach.
I jeszcze jedna pułapka, którą widać w widgecie powyżej: reguły ze znacznika <style> w osadzonym SVG obowiązują na całej stronie, a nie tylko wewnątrz tej grafiki. Klasa nazwana .ikona nadpisze wszystkie inne .ikona w dokumencie. Dlatego klasy w tym presecie mają celowo dziwaczne nazwy.
Droga trzecia: JavaScript
Skrypt zmieniający atrybuty w czasie — samodzielnie albo przez bibliotekę.
js
element.setAttribute("cx", nowaWartosc);
To jedyna droga, gdy animacja ma reagować zamiast po prostu grać: podążać za kursorem, zależeć od pozycji przewijania, od danych z API, od fizyki albo od decyzji użytkownika. Bibliotek jest sporo, w praktyce spotkasz głównie GSAP i anime.js.
Warto znać też Element.animate() — Web Animations API, wbudowane w przeglądarki. Daje kontrolę czasu podobną do biblioteki, bez dokładania kilkudziesięciu kilobajtów.
Do prostych rzeczy JavaScript jest jednak przerostem formy. Pulsujące koło nie potrzebuje skryptu, a każdy skrypt to coś, co może się nie wykonać.
Zwróć uwagę, że w playgroundzie tej lekcji nie da się przetestować tej trzeciej drogi — podgląd usuwa znacznik <script> przed wyświetleniem. To ta sama zasada, o której będzie lekcja o bezpieczeństwie: SVG jest kodem, więc kod z niego usuwamy.
Jak wybrać
Reguła, która sprawdza się w większości przypadków:
- Animacja ma żyć w pliku i działać wszędzie, także w
<img>i w tle → SMIL. - Animacja jest częścią interfejsu, ma reagować na
:hoveralbo być sterowana klasą → CSS. - Animacja ma zależeć od danych, przewijania, kursora albo mieć sterowaną oś czasu → JavaScript.
W praktyce metody się mieszają i nie ma w tym nic złego. Logo z animacją SMIL może stać na stronie, w której cała reszta ruchu jest w CSS.
Rzecz, o której nie wolno zapomnieć
Część osób ma zawroty głowy, mdłości albo napady migreny od ruchu na ekranie. System operacyjny pozwala im to zgłosić, a przeglądarka przekazuje tę informację dalej:
css
@media (prefers-reduced-motion: reduce) {
.puls-demo { animation: none; }
}
To nie jest ozdobnik dla purystów dostępności. Dla części odbiorców to różnica między korzystaniem ze strony a zamknięciem jej. Trzy linijki i temat załatwiony — a przy SMIL trzeba to obsłużyć skryptem, bo znaczniki animacji nie widzą zapytań medialnych.
Druga zasada z tej samej rodziny: nie animuj bez końca tego, co nie niesie informacji. Wskaźnik ładowania ma prawo się kręcić, bo mówi „pracuję". Logo kręcące się w kółko przez cały czas wizyty tylko męczy.
Podsumowanie
- SMIL to animacja w znacznikach, wewnątrz pliku; jako jedyna działa w
<img>i w tle. - Straszenie wycofaniem SMIL pochodzi sprzed dekady i jest nieaktualne.
- CSS daje znaną składnię,
:hoveri zapytania medialne, ale wymaga SVG wstawionego inline. - Nie każdy atrybut SVG da się animować w CSS; SMIL nie ma tego ograniczenia.
- Reguły
<style>wewnątrz osadzonego SVG działają na całą stronę. - JavaScript jest potrzebny wtedy, gdy animacja ma na coś reagować.
prefers-reduced-motionto nie ozdobnik — dla części odbiorców to warunek korzystania ze strony.
W następnej lekcji wracamy do stroke-dasharray z lekcji siódmej i składamy z niego najpopularniejszy efekt w całym SVG: linię, która rysuje się sama.
Do wypróbowania: w presecie SMIL dopisz do koła drugą animację, na przykład na promieniu: <animate attributeName="r" values="16; 6; 16" dur="1s" repeatCount="indefinite"/>. Dwie animacje na jednym kształcie działają równolegle i niezależnie — w CSS wymagałoby to jednej wspólnej klatkowej sekwencji.