
Як анімувати SVG підпис
Давайте подивімось, як можна анімувати SVG-підпис за допомогою пари десятків рядків JavaScript та CSS. У цій демонстрації я навчу вас використовувати JS-функцію для обчислення довжини SVG-шляху (path) та CSS-анімацію для анімування SVG-штрихів (stroke).
Готовий результат можна побачити на моєму CodePen.
SVG-підпис
Почнемо зі створення SVG-підпису. Я використовую Sketch, щоб намалювати SVG-шляхи для літер.
Ось як це виглядає в режимі редагування:

Наразі підпис містить 8 шляхів (paths) для різних частин підпису. Наприклад, один шлях відповідає літері «S», інший - крапці і так далі.
Після експорту SVG зі Sketch, я змінив послідовність шляхів так, щоб вони зʼявлялися саме в тому порядку, у якому мають анімуватися. Спершу літера “S”, потім крапка, потім літера “B” і так далі. Також я додав класи autograph та autograph__path для більш зручної Css-стилізації та маніпуляцій за допомогою JS.
Ось фінальний файл підпису:
<svg class="autograph" height="103" viewBox="0 0 424 103" width="424" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" transform="translate(2 2)">
<path class="autograph__path"
d="m52.9053119 30.5944651c4.4979146-5.981029 6.3597765-11.3263744 5.5855855-16.0360361-2.1621621-13.15315311-10.9863929-13.558429-15.4908974-13.558429-10.0900901 0-20 7.99987048-20.7253188 13.558429-3.0543891 23.4076405 31.8852386 28.5472234 30.7253188 52.441571-.9009009 18.5585586-12.9740033 27.7974004-25 29-12.6126126 1.2612613-28.33708674-6.8576105-27-18 .48048048-4.004004 5.81381381-7.6706707 16-11" />
<path class="autograph__path"
d="m61.9059048 93.3815042c1.7863267-3.215388-4.287184-4.6444494-4.6444494-1.4290614-.3572653 2.143592 2.8581227 4.6444494 4.6444494 1.4290614z" />
<path class="autograph__path" d="m102 1c-1.633522 27.1862259-3.3001883 44.8528926-5 53s-7.033145 22.1471074-16 42" />
<path class="autograph__path"
d="m100.288288 6.6036036c4.152508-3.963964 8.176532-5.945946 12.072072-5.945946 11.531532 0 17.63964 3.3423424 16.63964 14.3423424 0 13-12.06006 22.3543543-32 28 21.430945-5.8755744 31.400915 1.8721733 29.90991 23.2432432-1.081081 15.4954958-25.606607 24.6336338-48.90991 27.7567568 18.3783784-31.111111 44.546547-46.5975976 58-49 7.684578-1.3722461.201094 23.4415679-4 51 9.626744-23.6648293 10.754389-40.1268415 26.472991-48.7743243 3.062782-1.6849689 5.899902-2.8000991 9.527009-2.2256757 2.58117.4087788 5.287656.9554275 10 6-7-8-16.06468-6.1122883-19.527009-1.6121622-10.472991 13.6121622 15.527009 13.6121622 16.527009 29.6121622.666667 10.6666667-5.666667 16.3333333-19 17-16.664879 2.1642702 8.261928 6.47368 29-21 9.19448-12.1807945 18.19448-36.8474612 27-74-21.276288 33.987688-24.609621 65.6543547-10 95 21.886044-29.4751082 26.735893-49.2438774 35-51 9.609609-2.042042 6.726727 21.4504503 0 51 4.444444-39.2792794 18.42042-58.8078078 38-51-8.828829 2.1621621-15.315998 15.4560012-16.711712 28.1171176-1.126809 10.2217665 4.625073 22.8828824 11.711712 22.8828824 12.252252 0 19.279279-10.0010654 19.279279-20.5405401 0-23.0630631-9.234234-30.4594599-12.477477-30.4594599 12.432432 3.9639639 30.297297-6.8468469 31.198198 0 2.644012 20.0944903-19 51 5 51 22 0 19.936937-49.1981982 23-51 2.342343 8.6486486 18.480018-2.1232717 18 0-3.570281 15.7924726-11.376494 44.5410656-10 51 4.504505-13.1531532 17-47 45.900901-51.1711712 6.669031-.9625192 8.255066 5.4033441 3.963964 18.5585586 4.204205-13.3333334 2.882883-19.5195196-3.963964-18.5585586-13.059803 1.8329549-22.530745 8.0837151-28.69016 31.4759854-1.237235 12.5179014 1.692518 19.0829633 8.789259 19.6951858 4.616353.3982441 10.995909-1.7223734 19.138668-6.3618524" />
<path class="autograph__path" d="m178 30c11-4 54 6 73.734117 1.8554251" />
<path class="autograph__path" d="m419 1-21 27.333" />
<path class="autograph__path"
d="m140.729905 31.3135042c1.786326-3.215388-4.287184-4.6444494-4.64445-1.4290614-.357265 2.1435921 2.858123 4.6444494 4.64445 1.4290614z" />
<path class="autograph__path"
d="m360.729905 31.3135042c1.786326-3.215388-4.287184-4.6444494-4.64445-1.4290614-.357265 2.1435921 2.858123 4.6444494 4.64445 1.4290614z" />
</g>
</svg>Дуже важливо створювати SVG із контурами (strokes), оскільки саме їм ми будемо додавати анімацію. Кожен шлях або контур має свою довжину і ми використуємо це в нашій анімації.
JavaScript-обчислення
Щоб обчислити довжину контуру, можна використати приблизне вгадування 😁. У цьому випадку потрібно задіяти два dash-атрибути:
stroke-dasharray- робить контур пунктирним;stroke-dashoffset- зміщує позицію пунктиру за межі видимого шляху;
Ці дві властивості повинні бути рівні одна одної для того, щоб усе працювало як слід.
Але ми - програмісти, і нам не потрібно вгадувати, тож давайте обчислимо це програмно за допомогою JS.
Ось концепція того, як це має працювати:
- Спочатку задаємо загальну бажану тривалість анімації;
- Потім використовуємо функцію
getTotalLength()для обчислення загальної довжини всіх шляхів разом; - Далі розраховуємо тривалість анімації та затримки для кожного шляху пропорційно відношенню їхньої довжини до загальної;
- Потім встановлюємо
stroke-dasharrayтаstroke-dashoffset,щоб розташувати пунктирний контур поза межами видимого шляху; - Нарешті запускаємо анімацію, додавши до
bodyкласanimated;
Ось повна JavaScript-функція (з коментарями для легшого розуміння):
const calcPaths = (totalDur) => {
document.body.classList.add('animated')
// знаходимо всі шляхи SVG
const paths = document.querySelectorAll('.autograph__path')
// змінна для довжини всіх шляхів
let len = 0
// змінна для затримки анімації
let delay = 0
// перервати виконання, якщо елементів не знайдено
if (!paths.length) {
return false
}
// встановлюємо тривалість анімації за замовчуванням, якщо не задано (в секундах)
const totalDuration = totalDur || 7
// обчислюємо загальну довжину всіх шляхів
paths.forEach((path) => {
const totalLen = path.getTotalLength()
len += totalLen
})
paths.forEach((path) => {
const pathElem = path
// довжина поточного шляху
const totalLen = path.getTotalLength()
// тривалість анімації для поточного шляху
const duration = totalLen / len * totalDuration
// тривалість анімації і затримка
pathElem.style.animationDuration = `${duration < 0.2 ? 0.2 : duration}s`
pathElem.style.animationDelay = `${delay}s`
// встановлюємо dash-array і dash-offset відповідно до довжини шляху - так ховається лінія
pathElem.setAttribute('stroke-dasharray', totalLen)
pathElem.setAttribute('stroke-dashoffset', totalLen)
// встановлюємо затримку для наступного шляху - додано 0.2 секунди для більш реалістичного ефекту
delay += duration + 0.2
})
// додаємо клас 'animated' до body, щоб запустити анімацію
document.body.classList.add('animated')
return true
}
calcPaths(5)‼️ Обов’язково перевірте сумісність із браузерами, перш ніж це використовувати.
Css-анімація
Css-анімація полягає в тому, щоб встановити кінцеве значення stroke-dashoffset назад у нуль.
Я використав linear для animation-timing-function та forwards для animation-fill-mode.
Перша властивість робить анімацію лінійною, що, на мою думку, виглядає найприродніше.
Друга - змушує анімацію залишатися у фінальному стані (100%).
.autograph__path {
opacity: 0;
animation-timing-function: linear;
animation-fill-mode: forwards;
.animated & {
opacity: 1;
animation-name: line;
}
}
@keyframes line {
100% {
stroke-dashoffset: 0;
}
}Я використав opacity, щоб запобігти мерехтінню під час завантаження. Це працює краще в поєднанні з Critical Css.
Висновок
Ось і все, ми анімували SVG-підпис. Маючи трохи знань про SVG, JavaScript і CSS, ви можете створювати привабливі анімації малювання. В інтернеті є плагіни котрі створюють подібні анімації, але я завжди надаю перевагу меншому обсягу коду. Ця демонстрація зроблена менш ніж у 100 рядках коду.
Повне демо можна переглянути тут - CodePen