Najpopularniejszy efekt w SVG i najprostsza sztuczka w całym kursie
Podpis odręczny pojawiający się litera po literze. Wykres, który rysuje się przy przewinięciu strony. Ptaszek wskakujący do pola formularza. Wszystko to jest tym samym efektem i za wszystkim stoi jedna właściwość, którą znasz już z lekcji siódmej.
Zacznijmy od demistyfikacji, bo tu naprawdę nie ma magii.
Nic się nie rysuje
Linia istnieje od początku. Jest po prostu ukryta i stopniowo odsłaniana.
Cała sztuczka opiera się na dwóch krokach:
- Ustaw kreskę tak długą jak cała ścieżka — wtedy nie ma żadnej przerwy i linia wygląda normalnie.
- Przesuń ten wzór o całą długość — kreska wyjeżdża poza ścieżkę i linia znika.
Wartości pomiędzy dają częściowe odsłonięcie. To wszystko.
Suwak to nic innego jak
stroke-dashoffset. Przy 100 linii nie ma, przy 0 jest cała, a po drodze rysuje się od lewej. Przesuń go powoli w obie strony — zobaczysz, że tak samo dobrze potrafi się „odrysowywać".
Problem długości
Skoro kreska ma być dokładnie tak długa jak ścieżka, trzeba znać tę długość. A dla dowolnej krzywej Béziera nie da się jej policzyć w głowie.
Klasyczne rozwiązanie to JavaScript:
js
const dlugosc = sciezka.getTotalLength();
sciezka.style.strokeDasharray = dlugosc;
sciezka.style.strokeDashoffset = dlugosc;
Działa i przez lata było jedynym sposobem. Ma jednak wadę: efekt wymaga skryptu, więc bez JavaScriptu linia jest widoczna od razu.
Prostsza droga to atrybut, o którym wspominałem przy okazji problemu szwu:
html
<path d="..." pathLength="100"
stroke-dasharray="100"
stroke-dashoffset="100"/>
pathLength pozwala zadeklarować, że ścieżka „ma długość 100" — niezależnie od tego, ile wynosi naprawdę. Wszystkie wartości dasharray i dashoffset są od tej chwili liczone w tej umownej skali.
Zysk jest podwójny. Nie musisz nic mierzyć, a przy okazji liczysz w procentach: offset 40 to zawsze 40% ścieżki, w każdej grafice i przy każdym rozmiarze. Zmiana kształtu linii nie wymaga poprawiania animacji.
Wprawianie w ruch
Mając mechanizm, wystarczy zanimować jedną liczbę. Wszystkie trzy metody z poprzedniej lekcji nadają się tak samo.
W SMIL, gdy plik ma być samowystarczalny:
html
<animate attributeName="stroke-dashoffset"
values="100; 0; 0"
keyTimes="0; 0.6; 1"
dur="3s"
repeatCount="indefinite"/>
keyTimesrozkłada wartości w czasie. Przy 0.6 rysowanie zajmuje pierwsze 60% cyklu, a przez pozostałe 40% rysunek po prostu stoi gotowy. Bez tej pauzy animacja wracałaby do zera natychmiast i wyglądała nerwowo.
W CSS, gdy efekt ma reagować na najechanie:
css
.podpis { stroke-dasharray: 100; stroke-dashoffset: 100; }
.podpis:hover { stroke-dashoffset: 0; transition: stroke-dashoffset 1.2s ease; }
To bodaj najkrótszy sposób i wystarcza w większości przypadków interfejsowych.
W JavaScripcie, gdy rysowanie ma zależeć od pozycji przewijania albo od postępu jakiegoś procesu — wtedy po prostu ustawiasz strokeDashoffset na wartość wyliczoną z bieżącego stanu.
To samo, zastosowane inaczej
Kiedy zrozumiesz mechanizm, zauważysz go w miejscach, które wcale nie wyglądają na rysowanie.
Pierścień postępu to ta sama sztuczka. Szary okrąg to tło, pomarańczowy ma kreskę o długości równej procentowi. Przy
pathLength="100"długość kreski jest procentem — bez liczenia obwodu, bezgetTotalLength, bez skryptu.
Obrót o minus dziewięćdziesiąt stopni przesuwa punkt startowy na górę, bo domyślnie okrąg zaczyna się po prawej stronie. To jedyna nieoczywista linijka w całym rozwiązaniu.
Cztery rzeczy, które zaskakują
Kierunek zależy od ścieżki. Linia odsłania się od punktu M w stronę końca. Jeśli rysuje się „od złej strony", nie kombinuj z ujemnym offsetem — odwróć kolejność punktów w d.
Podścieżki rysują się równocześnie. Jeśli w d jest kilka komend M, wszystkie fragmenty odsłaniają się jednocześnie, bo wzór kreskowania działa na całej ścieżce naraz. Żeby litery podpisu pojawiały się kolejno, każda musi być osobnym elementem <path> z własnym opóźnieniem.
Zaokrąglone zakończenie wystaje. Przy stroke-linecap="round" odsłonięta kreska jest dłuższa o połowę grubości z każdej strony, więc przy offsecie równym 100 może być widoczna resztka. Przy grubych liniach ustaw offset odrobinę powyżej długości albo użyj butt.
Efekt jest tani. Animacja dashoffset nie zmienia geometrii ani układu strony — przeglądarka tylko przerysowuje kontur. To jedna z niewielu animacji SVG, które można puszczać w wielu instancjach bez obaw o wydajność.
Podsumowanie
- Linia nie jest rysowana, tylko odsłaniana przez przesuwanie wzoru kreskowania.
- Kreska równa długości ścieżki plus offset równy tej długości daje linię niewidoczną.
pathLength="100"zwalnia z mierzenia ścieżki i pozwala operować procentami.getTotalLength()to starsza droga, wymagająca JavaScriptu.- Animować można w SMIL, CSS albo JS — wybór zależy od tego, czy efekt ma reagować.
- Kierunek odsłaniania wynika z kolejności punktów w
d; podścieżki rysują się równocześnie. - Ten sam mechanizm obsługuje wskaźniki postępu i pierścienie procentowe.
W następnej lekcji przestajemy powtarzać kod: defs, use i symbol, czyli jak zrobić dwadzieścia ikon z jednego pliku.
Do wypróbowania: w presecie pierścień postępu usuń atrybut pathLength="100". Pierścień prawie zniknie, bo kreska o długości 65 jednostek to teraz zaledwie jedna piąta prawdziwego obwodu, który wynosi około 345. To najkrótszy dowód na to, do czego ten atrybut naprawdę służy.