
✨ Animacja linii i zamkniętych konturów SVG na czystym CSS
Animacja obrysu SVG to jeden z tych trików, które zamieniają statyczną ikonę w żywą ilustrację. Na pewno widzieli już Państwo ten efekt: kontur logo płynnie się rysuje, jakby niewidzialne pióro kreśliło kształt od początku do końca. Wygląda kosztownie, a robi się go na czystym CSS.
Problem w tym, że większość poradników zatrzymuje się na najprostszym przypadku: otwarta ścieżka, jedna linia, animacja od początku do końca. Ale prawdziwa grafika to zamknięte kontury, łamane kształty i kierunki rysowania, których projektant nie kontrolował. Ścieżka SVG może zaczynać się gdziekolwiek, a Państwo potrzebują, żeby rysowała się zgodnie z ruchem wskazówek zegara i z estetycznego punktu startowego.
Poniżej pełny zestaw technik: od podstawowej animacji po podwójne linie i pełną kontrolę nad punktem początkowym i końcowym. Wszystko na czystym CSS, bez bibliotek i pomiarów w runtime. Metody sprawdzone podczas prac nad wtyczką SVG Divider i działają w każdej nowoczesnej przeglądarce.
💡 Szybki przegląd:
- Proszę poznać długość ścieżki SVG przez
getTotalLength()lub Illustrator i wpisać liczbę w CSS. - Proszę ustawić
stroke-dasharray: LENGTHi animowaćstroke-dashoffsetodLENGTHdo0. - Aby odwrócić kierunek, proszę zamienić miejscami kreskę i odstęp w
stroke-dasharrayi przesunąćstroke-dashoffsetdo przodu. - Proszę przesunąć punkt początkowy, dodając do
stroke-dashoffsetpołowę (lub dowolny ułamek) długości. - Proszę uruchomić animację „od środka na zewnątrz": start od
HALF_LENGTH, koniec naFULL_LENGTH. - Proszę skonfigurować podwójne linie przez połówkowy
stroke-dasharrayi ćwierć-przesunięciestroke-dashoffset.
Baza techniczna: kreski, odstępy i długość ścieżki
Podstawą każdej animacji SVG są dwie właściwości CSS: stroke-dasharray i stroke-dashoffset. Pierwsza definiuje wzór „kreska-odstęp" wzdłuż konturu, druga przesuwa ten wzór. Jeśli zrobi się kreskę równą pełnej długości ścieżki, a potem zaanimuje przesunięcie, linia „narysuje się" na oczach.
Kluczowy krok przed jakąkolwiek animacją: poznać pełną długość ścieżki. Sposoby:
- JavaScript:
document.querySelector('path').getTotalLength(), jedno wywołanie w konsoli, liczba jest wpisywana w CSS na sztywno. Żadnego runtime. - Illustrator: panel „Informacje o dokumencie" pokazuje długość zaznaczonej ścieżki.
- Własny skrypt: jeśli ścieżek są dziesiątki lub setki, warto napisać automatyczne przejście i oznaczenie długości.
Ważny niuans: getTotalLength() i Illustrator mogą dać nieco różne liczby dla tej samej ścieżki. Przyczyną jest różna precyzja obliczeń. Rozbieżność zwykle mieści się w granicach 1-2 jednostek i nie wpływa na wizualny odbiór.
Proszę sprawdzić geometrię ścieżki pod kątem błędów. Kierunek rysowania i punkt początkowy zależą od tego, jak projektant zbudował krzywą w edytorze, to normalne. Poniżej nauczymy się kontrolować jedno i drugie bez edycji samego SVG.
Podstawowa animacja: rysujemy linię od początku do końca
Najprostszy przypadek: otwarta ścieżka o długości, powiedzmy, 100 jednostek. Ustawiamy kreskę na całą długość i animujemy przesunięcie od 100 do 0:
1 @keyframes reveal { 2 to { 3 stroke-dashoffset: 0; 4 } 5 } 6 svg path { 7 stroke-dashoffset: 100; 8 stroke-dasharray: 100; 9 animation: reveal 1s ease-in-out 0s forwards; 10 }
Co tu się dzieje: stroke-dasharray: 100 ustawia 100 jednostek ciągłej linii i 100 jednostek pustki (druga wartość domyślnie równa się pierwszej). stroke-dashoffset: 100 przesuwa wzór tak, że widoczna część wychodzi poza ścieżkę, linia jest niewidoczna. Animacja sprowadza przesunięcie do zera i kreska wsuwa się na miejsce.
Kilka praktycznych uwag:
- Proszę zastąpić
FULL_LENGTHrzeczywistą liczbą bez jednostek miary. Silnik CSS nie rozumiepxczyemwewnątrzstroke-dasharray. - Selektor
svg pathjest dla jednego konturu. Jeśli w SVG jest kilka ścieżek, proszę użyć klas, ID lub pseudoklas w rodzajupath:nth-of-type(3). Narzędzia do debugowania::nth Testeri nthmaster.com. - Nazwa
@keyframesmusi być unikalna dla każdego wariantu animacji. Różne ścieżki często potrzebują własnych klatek kluczowych. - Proszę unikać ujemnych wartości
stroke-dashoffset: Safari przy ujemnym przesunięciu może migać lub pokazywać artefakty.
Kontrola kierunku: rewers rysowania
Domyślnie animacja idzie od początku ścieżki do końca, tam, gdzie projektant poprowadził krzywą. Ale często potrzebne jest odwrotnie: żeby zamknięty kontur rysował się zgodnie z ruchem wskazówek zegara, a nie przeciwnie.
Rozwiązanie: odwrócić wzór kreski: linia startuje jako niewidoczna (0 kreski, 100 odstępu) i staje się widoczna (100 kreski, 0 odstępu), a przesunięcie ciągnie ją z powrotem:
1 @keyframes reversed { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 0; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 100; 9 } 10 } 11 svg path { 12 animation: reversed 1s ease-in-out 0s forwards; 13 }
Mechanika działa dzięki cykliczności wzoru kreski: ciągła linia materializuje się na końcu ścieżki, a jej kopia idzie w lewo za początek i pozostaje niewidoczna. To samo dzieje się na zamkniętych konturach: kopia kreski pojawia się „przed" początkiem i nie przeszkadza w odbiorze.
Istnieje alternatywne podejście, krótsze i bez manipulacji tablicą:
1 @keyframes alternative-reversed { 2 from { 3 stroke-dashoffset: 100; 4 } 5 to { 6 stroke-dashoffset: 200; 7 } 8 } 9 svg path { 10 stroke-dasharray: 100; 11 animation: alternative-reversed 1s ease-in-out 0s forwards; 12 }
Tutaj stroke-dasharray jest ustalony na pełną długość, a przesunięcie zmienia się od 100 do 200. Rezultat jest ten sam, linia rysowana jest w odwrotnym kierunku. Proszę użyć wariantu, który jest dla Pana/Pani bardziej intuicyjny.
Przesunięcie punktu początkowego
Zamknięta ścieżka przypomina kolej obwodową: pociąg może wyruszyć z dowolnej stacji. Zadanie polega na przesunięciu początku animacji w estetyczny punkt, bez dotykania samej geometrii.
Start z przeciwnej strony
Dla symetrycznych konturów wystarczy przesunięcie o połowę długości:
1 @keyframes start-from-other-side { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 50; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 50; 9 } 10 } 11 svg path { 12 animation: start-from-other-side 1s ease-in-out 0s forwards; 13 }
Kierunek rysowania pozostaje początkowy, ale wizualnie animacja zaczyna się z przeciwległego końca.
Odwrócenie kierunku i dowolny start
Aby jednocześnie odwrócić kierunek i przesunąć punkt startowy, należy dodać pełną długość do końcowego przesunięcia:
1 @keyframes other-side-and-reverse { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 50; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 150; 9 } 10 } 11 svg path { 12 animation: other-side-and-reverse 1s ease-in-out 0s forwards; 13 }
Dla całkowicie dowolnego punktu proszę wstawić dowolną wartość zamiast 50. Metodą prób i błędów (plus minus 5-10 jednostek) znajduje się optymalną pozycję. W jednym z projektów punkt startowy na ikonce bitów Twitcha został przesunięty o 17 pikseli, liczba nie jest ładna, ale wizualnie idealna.
Animacja „od środka na zewnątrz"
Linia rośnie od środka w obie strony jednocześnie, to klasyczny zabieg dla logotypów i infografik:
1 @keyframes inside-out { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 50; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 100; 9 } 10 } 11 svg path { 12 animation: inside-out 1s ease-in-out 0s forwards; 13 }
Przesunięcie startuje od połowy długości (środek ścieżki) i zmierza do pełnej długości, ciągnąc za sobą kreskę. Dla niesymetrycznych kształtów punkt startu można dodatkowo przesunąć:
1 @keyframes custom-inside-out { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 84; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 134; 9 } 10 }
Tutaj 84 = HALF_LENGTH + 34. Stała 34 została dobrana ręcznie dla konkretnego kształtu. Nie ma uniwersalnej recepty, proszę próbować, obserwować, korygować.
Animacja „z zewnątrz do środka": podwójne pióro
Podejście przeciwne: linia rysowana jest z dwóch końców jednocześnie, schodząc się do środka. Na otwartych konturach daje to efekt „dwóch piór":
1 @keyframes outside-in { 2 from { 3 stroke-dasharray: 0 100; 4 } 5 to { 6 stroke-dasharray: 50 0; 7 } 8 } 9 svg path { 10 animation: outside-in 1s ease-in-out 0s forwards; 11 }
Kreska sięga tylko do połowy długości, przerwa zamyka się dwukrotnie szybciej niż w podstawowej animacji. stroke-dashoffset nie jest tu potrzebny: wzorzec „0 przerwy" w stanie końcowym samoczynnie sprawia, że obie połówki kreski się zwierają.
Pełna kontrola: punkt początkowy i końcowy
Gdy jeden kierunek i punkt startowy to za mało, można sterować obiema granicami rysowania. Dwie ruchome głowice linii zbiegają się we wspólnym punkcie docelowym:
1 @keyframes custom-start-end { 2 from { 3 stroke-dasharray: 0 100; 4 stroke-dashoffset: 30; 5 } 6 to { 7 stroke-dasharray: 100 0; 8 stroke-dashoffset: 80; 9 } 10 } 11 svg path { 12 animation: custom-start-end 1s ease-in-out 0s forwards; 13 }
Wartości 30 i 80 są dowolne; przesunięcie from jest mniejsze niż przesunięcie to, to jedyna sztywna reguła. Jeśli punkty są blisko, jeden segment leci szybko, drugi pełznie wolno, to normalne, a nawet efektowne.
Proszę nie bać się wychodzić poza pełną długość w wartości to. stroke-dashoffset: 130 przy długości 100 jest legalne, to po prostu przesuwa cykl kresek na drugie okrążenie. Najważniejsze to unikać wartości ujemnych.
Podwójne linie i efekty specjalne
Najbardziej elastyczny tryb: kreski o połowicznej długości z przesunięciem o ćwiartkę. Każda ścieżka otrzymuje dwie głowice linii poruszające się niezależnie:
1 @keyframes double-lines { 2 from { 3 stroke-dasharray: 0 50; 4 stroke-dashoffset: 25; 5 } 6 to { 7 stroke-dasharray: 50 0; 8 stroke-dashoffset: 50; 9 } 10 } 11 svg path { 12 animation: double-lines 1s ease-in-out 0s forwards; 13 }
Dla złożonych kształtów tablica kresek może składać się z kilku komponentów. Suma wszystkich wartości tablicy musi być równa pełnej długości. Rzeczywisty przykład dla znaku nieskończoności:
1 @keyframes infinity-double-lines { 2 from { 3 stroke-dasharray: 0 53 0 47; 4 stroke-dashoffset: 37; 5 } 6 to { 7 stroke-dasharray: 53 0 47 0; 8 stroke-dashoffset: 60; 9 } 10 } 11 svg .infinity { 12 animation: infinity-double-lines 8s ease-in-out 0s alternate infinite; 13 stroke: #8D69D8; 14 }
Cztery komponenty tablicy (53 + 47 = 100 = pełna długość) zamieniają się miejscami między from i to. Animacja jest zapętlona (infinite) i odwrócona (alternate), co daje medytacyjny, oddechowy kontur, który nigdy nie powtarza się tak samo.
Wideo: animacja SVG w praktyce
Aby zobaczyć wszystkie opisane techniki na żywo i zrozumieć niuanse konfiguracji, proszę obejrzeć ten anglojęzyczny tutorial:
Autor pokazuje krok po kroku tworzenie animowanej ilustracji SVG od eksportu z Figma po finalne szlify w CSS. Znaczniki czasu w opisie pozwalają przejść od razu do potrzebnego rozdziału.
⁉️🤔 Często zadawane pytania
Po co znać długość ścieżki z góry, skoro jest getTotalLength()?
getTotalLength()to JavaScript, a naszym celem jest czysty CSS bez zależności od runtime’u. Mierzy się długość RAZ (w konsoli lub Illustratorze), wpisuje wartość na sztywno w CSS i animacja działa bez ani jednej linii JS.
Czy można animować kilka ścieżek jedną animacją?
Tak, jeśli mają tę samą długość i pożądane zachowanie. W praktyce ścieżki rzadko się pokrywają, prościej jest zdefiniować dla każdej własny
@keyframeslub użyć zmiennych CSS z różnymi wartościami długości.
Dlaczego Safari miga przy ujemnym stroke-dashoffset?
To znany bug renderowania WebKit: ujemne wartości przesunięcia są czasem interpretowane jako natychmiastowy reset do 0. Rozwiązanie: zawsze utrzymywać
stroke-dashoffset≥ 0, a jeśli potrzebne jest przesunięcie, dodać pełną długość zamiast schodzić na minus.
Co zrobić, jeśli animacja „szarpie" na początku lub na końcu?
Proszę dodać
forwardsdoanimation(zachowuje stan końcowy) i usunąćalternate, jeśli rewers nie jest potrzebny. Proszę też sprawdzić, czy nie ma konfliktu z innymi regułami CSS dla tego samego elementu, na przykładtransitionna tej samej właściwości.
Czy działa to z stroke-dasharray na zamkniętych konturach o złożonej geometrii?
Tak, mechanika jest taka sama dla wszystkich ścieżek SVG: prostych, krzywych Béziera, zamkniętych poligonów. Różnica polega tylko na tym, że na zamkniętym konturze nie ma wizualnego „początku" i „końca", dlatego kontrola punktu startowego jest szczególnie ważna dla estetyki.
Czy warto pisać animację ręcznie, skoro są biblioteki?
Krótka odpowiedź: zależy od skali. Dla pojedynczej ikony na landing page’u ręczne sterowanie daje idealny rezultat bez zbędnych zależności. Piętnaście minut na dobranie przesunięcia i kontur rysuje się dokładnie tak, jak Państwo zaplanowali, a nie jak zdecydował twórca biblioteki.
Gdy robiliśmy separatory SVG dla Elementora, ręczne sterowanie zwróciło się potrójnie. Wtyczka wykorzystuje dziesiątki animowanych separatorów, każdy z indywidualnie skonfigurowanymi obrysami. Żadna biblioteka nie dałaby takiej kontroli nad estetyką.
Na techniki z tego artykułu nakładają się dodatkowo:
- Sterowanie stanami animacji przez JavaScript (start/stop/restart);
- Leniwy start przez
Intersection Observer: kontur rysuje się dopiero, gdy trafi do viewportu; - Łańcuchy animacji przez
animation-delay; - Niestandardowe funkcje wygładzania (
cubic-bezier()); - Dodatkowa praca z przezroczystością w
@keyframes; - Elastyczna animacja linii przerywanych („ścieżka mrówki").
Proszę wziąć za podstawę szablon z artykułu, podstawić własne wartości długości i eksperymentować z cubic-bezier(). Odpowiednio dobrana funkcja wygładzania zmienia odbiór animacji silniej niż przesunięcie punktu startowego o kilka pikseli.



