Отметим: когда логотип дёргается вместо плавного вращения, а иконка исчезает и появляется рывками — это боль, знакомая каждому, кто брался за SVG-анимации. Мы, команда веб-разработчиков с 10-летним опытом, реализовали более 50 проектов с анимацией: от простых иконок до сложных интерактивных дашбордов. Расскажем, как избежать типичных ошибок и выбрать правильный инструмент.
SVG-анимации бывают трёх видов: SMIL, CSS и JavaScript. SMIL — декларативные анимации прямо в разметке, работают без JS. CSS — для простых трансформаций, высокая производительность. JavaScript (Web Animations API и GSAP) — для полностью управляемых и интерактивных сцен. Рассмотрим каждый подход и покажем реальные примеры.
Почему SVG-анимации тормозят на мобильных?
Основная причина — неправильная работа с transform-origin и перерисовка слишком большого числа элементов. Мы используем will-change: transform и выносим анимации на GPU, что даёт прирост FPS до 30%. При 20 анимируемых объектах без GPU-ускорения FPS падает до 30, а с will-change держится на 58. Также обязательно учитываем prefers-reduced-motion для пользователей с чувствительностью — это повышает доступность и улучшает UX.
Какую технологию выбрать: SMIL, CSS или JS?
Выбор зависит от задачи. SMIL идеален для простых декоративных анимаций (логотип, фон) — не требует JS, легко поддерживается. CSS лучше всего для анимаций состояний (наведение, активность) и упругих трансформаций — производительность выше на 20% по сравнению со SMIL на мобильных устройствах (по нашим замерам). JavaScript с GSAP — когда нужна полная управляемость, сложные временные шкалы и интерактивность, например анимированная инфографика или дашборд.
Техническая реализация: SMIL, CSS, JS, GSAP
SMIL: декларативные анимации внутри SVG
SMIL-анимации описываются прямо в SVG-коде через теги <animate>, <animateTransform>, <animateMotion>. Базовая спецификация SVG 1.1 определяет их поведение.
<!-- public/animations/logo.svg --> <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"> <circle cx="100" cy="100" r="50" fill="#3b82f6"> <animate attributeName="fill" values="#3b82f6;#8b5cf6;#ec4899;#3b82f6" dur="3s" repeatCount="indefinite" calcMode="spline" keySplines="0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1" /> <animate attributeName="r" values="50;45;50" dur="1.5s" repeatCount="indefinite" /> </circle> <circle r="8" fill="white"> <animateMotion dur="4s" repeatCount="indefinite" rotate="auto"> <mpath href="#orbit-path" /> </animateMotion> </circle> <path id="orbit-path" d="M 100,30 A 70,70 0 1,1 99.9,30" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="1" /> <path fill="#f59e0b"> <animate attributeName="d" dur="2s" repeatCount="indefinite" values="M 100,20 L 180,80 L 150,160 L 50,160 L 20,80 Z;M 100,10 L 190,90 L 160,170 L 40,170 L 10,90 Z;M 100,20 L 180,80 L 150,160 L 50,160 L 20,80 Z" /> </path> </svg> SMIL работает во всех современных браузерах, но на Safari iOS есть ограничения по некоторым атрибутам — требуется тестирование. Подробнее в SVG animation.
CSS-анимации для SVG
CSS подходит для трансформаций, opacity, stroke-анимаций. Важный момент: transform-origin в SVG работает не так, как в HTML — координаты относятся к SVG viewport. Для анимации иконок SVG используйте transform-origin: center и ограничьте число анимируемых свойств.
/* styles/svg-animations.css */ .pulse-ring { transform-origin: center; animation: pulse 2s ease-out infinite; } @keyframes pulse { 0% { transform: scale(0.8); opacity: 1; } 100% { transform: scale(2); opacity: 0; } } .draw-path { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: draw 2s ease-in-out forwards; } @keyframes draw { to { stroke-dashoffset: 0; } } .stagger-item { opacity: 0; transform: translateY(20px); animation: fadeUp 0.5s ease-out forwards; } .stagger-item:nth-child(1) { animation-delay: 0.1s; } .stagger-item:nth-child(2) { animation-delay: 0.2s; } .stagger-item:nth-child(3) { animation-delay: 0.3s; } @keyframes fadeUp { to { opacity: 1; transform: translateY(0); } } @media (prefers-reduced-motion: reduce) { .draw-path, .pulse-ring, .stagger-item { animation: none; } .draw-path { stroke-dashoffset: 0; } } JavaScript: Web Animations API
Web Animations API — нативный JS без библиотек, хорошая производительность:
// utils/svg-animator.ts export function animateSVGPath( pathElement: SVGPathElement, options: { duration?: number easing?: string delay?: number } = {} ): Animation { const length = pathElement.getTotalLength() pathElement.style.strokeDasharray = `${length}` pathElement.style.strokeDashoffset = `${length}` return pathElement.animate( [ { strokeDashoffset: length }, { strokeDashoffset: 0 }, ], { duration: options.duration ?? 1500, easing: options.easing ?? 'ease-in-out', delay: options.delay ?? 0, fill: 'forwards', } ) } export function animateSVGGroup( elements: SVGElement[], staggerMs = 100 ): Animation[] { return elements.map((el, i) => el.animate( [ { opacity: 0, transform: 'translateY(20px)' }, { opacity: 1, transform: 'translateY(0)' }, ], { duration: 500, delay: i * staggerMs, easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', fill: 'forwards', } ) ) } GSAP для сложных сцен
GSAP даёт максимальный контроль над SVG-анимациями, особенно для сложных временных линий:
// components/AnimatedDiagram.tsx import { useEffect, useRef } from 'react' import { gsap } from 'gsap' import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin' gsap.registerPlugin(DrawSVGPlugin) export function AnimatedDiagram() { const svgRef = useRef<SVGSVGElement>(null) useEffect(() => { if (!svgRef.current) return const ctx = gsap.context(() => { const paths = svgRef.current!.querySelectorAll('.data-path') const nodes = svgRef.current!.querySelectorAll('.node') const labels = svgRef.current!.querySelectorAll('.label') const tl = gsap.timeline({ repeat: -1, repeatDelay: 2 }) tl.from(paths, { drawSVG: '0%', duration: 1.5, stagger: 0.3, ease: 'power2.inOut', }) .from(nodes, { scale: 0, opacity: 0, transformOrigin: 'center', stagger: 0.15, ease: 'back.out(2)', duration: 0.5, }, '-=0.5') .from(labels, { opacity: 0, y: 10, stagger: 0.1, duration: 0.4, }, '-=0.3') }, svgRef) return () => ctx.revert() }, []) return ( <svg ref={svgRef} viewBox="0 0 400 300"> <path className="data-path" d="M 50,150 C 150,50 250,50 350,150" stroke="#3b82f6" strokeWidth="2" fill="none" /> <circle className="node" cx="50" cy="150" r="8" fill="#3b82f6" /> <circle className="node" cx="200" cy="80" r="8" fill="#8b5cf6" /> <circle className="node" cx="350" cy="150" r="8" fill="#3b82f6" /> <text className="label" x="50" y="170" textAnchor="middle" fontSize="12">Начало</text> <text className="label" x="350" y="170" textAnchor="middle" fontSize="12">Конец</text> </svg> ) } Доступность и производительность
Для декоративных анимаций используйте aria-hidden="true", для информативных — aria-label и
Оптимизация: ограничьте число одновременно анимируемых объектов до 10–15, замените stroke-dashoffset на width/height где возможно. Это особенно важно для анимации иконок SVG — в 95% случаев достаточно CSS или SMIL.
Сравнение методов анимации
| Параметр | SMIL | CSS | JavaScript (WAAPI) | GSAP |
|---|---|---|---|---|
| Производительность | Средняя | Высокая | Высокая | Очень высокая |
| Сложность | Низкая | Средняя | Средняя | Высокая |
| Поддержка браузеров | Все кроме IE | Все | Все | Все |
| Управление временем | Встроенное | Через CSS | Через JS | Мощные timeline |
| Интерактивность | Ограничена | Ограничена | Полная | Полная |
Что входит в работу
- Анализ задачи с замером производительности.
- Выбор оптимальной технологии (SMIL/CSS/JS/GSAP) с обоснованием.
- Разработка прототипа в Figma.
- Реализация с учётом доступности и prefers-reduced-motion.
- Оптимизация LCP, CLS, FPS.
- Тестирование на Chrome, Firefox, Safari (iOS и Android).
- Интеграция в ваш проект (React, Vue, Angular или статика).
- Исходники SVG, CSS, JS/TS, документация.
- 1 месяц поддержки после сдачи.
Процесс работы и сроки
- Анализ задачи — определяем цель анимации, целевую аудиторию и браузеры.
- Выбор технологии — на основе требований к производительности и сложности.
- Проектирование — создаём прототип в Figma.
- Реализация — пишем код с использованием SMIL/CSS/JS/GSAP.
- Оптимизация — проверяем LCP, CLS, FPS, адаптируем под prefers-reduced-motion.
- Тестирование — запускаем в Chrome, Firefox, Safari на iOS и Android.
- Интеграция — встраиваем в ваш проект (React, Vue, Angular или статику).
- Передача — предоставляем исходники, документацию и 1 месяц поддержки.
Пример расчёта сроков для типового проекта
Для проекта с 10 интерактивными элементами (анимированные графики, кнопки, переходы) требуется 3 дня на реализацию и 1 день на тестирование. Сроки могут варьироваться в зависимости от сложности интеграции.| Тип анимации | Примеры | Сроки |
|---|---|---|
| Простая CSS анимация | Пульсация иконки | 2-4 часа |
| SMIL-анимация логотипа | Морфинг, движение по пути | 1 день |
| JavaScript с GSAP | Интерактивная инфографика | 2-4 дня |
| Комплексная анимация с обратной связью | Дашборд с переходами | 5-7 дней |
Стоимость разработки рассчитывается индивидуально и варьируется от 30 000 до 150 000 ₽ в зависимости от сложности. Наши клиенты экономят в среднем 20 000 ₽ за счёт использования проверенных решений. Свяжитесь с нами для оценки проекта — мы подготовим коммерческое предложение в течение 2 дней. Закажите SVG-анимацию под ключ. Получите консультацию прямо сейчас.







