SVG-элементы обладают двумя основными цветовыми характеристиками:
stroke и fill. Библиотека Vivus управляет в
первую очередь процессом прорисовки контуров через манипуляцию
stroke-dasharray и stroke-dashoffset, однако
изменение цвета анимации реализуется внешними средствами — CSS,
JavaScript и SVG-фильтрами.
Анимация цвета в связке с рисованием контура позволяет создавать визуально сложные эффекты: постепенное проявление логотипов, переходы состояния интерфейсных иконок, индикацию прогресса и динамическую стилизацию элементов.
Наиболее простой механизм изменения цвета основан на CSS-переходах:
.icon path {
stroke: #3498db;
fill: transparent;
transition: stroke 0.6s ease, fill 0.6s ease;
}
.icon.is-active path {
stroke: #e74c3c;
fill: #e74c3c;
}
При изменении класса элемент плавно изменяет цвет без необходимости вмешательства в Vivus-анимацию.
Прямое управление стилями позволяет синхронизировать цвет с фазами анимации:
const svg = document.querySelector('#icon');
svg.style.stroke = '#2ecc71';
svg.style.fill = 'transparent';
setTimeout(() => {
svg.style.stroke = '#9b59b6';
svg.style.fill = '#9b59b6';
}, 800);
Такой подход часто применяется при необходимости точного тайминга относительно анимации прорисовки.
Vivus предоставляет механизм обратных вызовов, который позволяет привязывать изменения цвета к прогрессу отрисовки.
new Vivus('my-svg', {
duration: 120,
type: 'delayed',
onReady: function (obj) {
obj.el.classList.add('animating');
},
onComplete: function (obj) {
obj.el.classList.add('completed');
}
});
.animating path {
stroke: #34495e;
}
.completed path {
stroke: #1abc9c;
fill: #1abc9c;
}
Цветовая логика разделяется на состояния: во время анимации и после завершения.
Vivus не предоставляет прямого API прогресса в процентах, однако
возможно использовать setFrame или кастомные интерполяции
для контроля состояния.
const vivus = new Vivus('my-svg', {
duration: 200,
type: 'oneByOne'
});
function updateColor(frame) {
const progress = frame / 200;
const r = Math.floor(52 + progress * 200);
const g = Math.floor(152 - progress * 100);
const b = Math.floor(219);
vivus.el.querySelectorAll('path').forEach(path => {
path.style.stroke = `rgb(${r}, ${g}, ${b})`;
});
}
Цвет формируется на основе линейной интерполяции, что позволяет связать визуальную динамику с ходом прорисовки.
Поскольку Vivus управляет stroke-dashoffset, это
значение может использоваться как индикатор состояния для изменения
цвета через CSS-переменные.
.icon path {
stroke: var(--stroke-color, #2980b9);
transition: stroke 0.3s linear;
}
document.documentElement.style.setProperty('--stroke-color', '#8e44ad');
Изменение переменной позволяет синхронно менять цвет у всех элементов SVG без перебора DOM.
Типичная практика — отделение анимации обводки и заливки по времени.
new Vivus('logo', {
duration: 150,
type: 'delayed',
onComplete: function (obj) {
obj.el.querySelectorAll('path').forEach((p, i) => {
setTimeout(() => {
p.style.fill = '#f1c40f';
}, i * 100);
});
}
});
Такой подход создаёт эффект «оживания» логотипа после завершения рисования контура.
SVG поддерживает градиенты, которые могут динамически изменяться во время работы Vivus.
<linearGradient id="grad">
<stop offset="0%" stop-color="#3498db">
<animate attributeName="stop-color"
values="#3498db;#e74c3c;#2ecc71"
dur="3s"
repeatCount="indefinite"/>
</stop>
</linearGradient>
path {
stroke: url(#grad);
}
Градиентная анимация работает независимо от Vivus, но визуально усиливает эффект прорисовки.
При типе анимации oneByOne каждый сегмент пути может
получать индивидуальный цвет.
new Vivus('icon', {
type: 'oneByOne',
duration: 200,
onReady: function (obj) {
const paths = obj.el.querySelectorAll('path');
paths.forEach((path, index) => {
path.style.stroke = `hsl(${index * 40}, 70%, 50%)`;
});
}
});
Цветовое кодирование сегментов усиливает восприятие структуры SVG.
Повторный запуск Vivus часто сопровождается сбросом состояния. Цвет можно изменять синхронно с повторной инициализацией:
function restartAnimation(vivusInstance) {
vivusInstance.reset();
vivusInstance.el.querySelectorAll('path').forEach(p => {
p.style.stroke = '#95a5a6';
p.style.fill = 'transparent';
});
vivusInstance.play();
}
Такой подход обеспечивает визуальную консистентность при многократных запусках.
Фильтры позволяют изменять цвет без прямого редактирования
stroke и fill.
<filter id="colorShift">
<feColorMatrix type="matrix"
values="1 0 0 0 0
0 0.8 0 0 0
0 0 0.8 0 0
0 0 0 1 0"/>
</filter>
svg {
filter: url(#colorShift);
}
Фильтрация применяется ко всему SVG и может комбинироваться с Vivus-анимацией без конфликтов.
Система состояний остаётся наиболее масштабируемым подходом для сложных интерфейсов.
.icon path {
stroke: #7f8c8d;
}
.icon.state-draw path {
stroke: #3498db;
}
.icon.state-done path {
stroke: #2ecc71;
}
const icon = document.querySelector('.icon');
icon.classList.add('state-draw');
setTimeout(() => {
icon.classList.remove('state-draw');
icon.classList.add('state-done');
}, 1200);
Разделение логики состояний позволяет изолировать анимацию Vivus от визуальных эффектов.
Для плавных переходов между цветами используется линейная интерполяция в RGB или HSL.
function lerp(a, b, t) {
return a + (b - a) * t;
}
function animateColor(el, from, to, duration) {
const start = performance.now();
function frame(time) {
const t = Math.min((time - start) / duration, 1);
const r = Math.round(lerp(from.r, to.r, t));
const g = Math.round(lerp(from.g, to.g, t));
const b = Math.round(lerp(from.b, to.b, t));
el.style.stroke = `rgb(${r},${g},${b})`;
if (t < 1) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
На практике цветовая анимация в Vivus-проектах строится как комбинация трёх уровней:
Такая архитектура позволяет разделять визуальную и поведенческую части SVG-анимации без потери контроля над финальным результатом