Анимация изменения цвета

SVG-элементы обладают двумя основными цветовыми характеристиками: stroke и fill. Библиотека Vivus управляет в первую очередь процессом прорисовки контуров через манипуляцию stroke-dasharray и stroke-dashoffset, однако изменение цвета анимации реализуется внешними средствами — CSS, JavaScript и SVG-фильтрами.

Анимация цвета в связке с рисованием контура позволяет создавать визуально сложные эффекты: постепенное проявление логотипов, переходы состояния интерфейсных иконок, индикацию прогресса и динамическую стилизацию элементов.


Базовые способы изменения цвета SVG

CSS-переходы для stroke и fill

Наиболее простой механизм изменения цвета основан на 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-анимацию.


Inline-изменение через JavaScript

Прямое управление стилями позволяет синхронизировать цвет с фазами анимации:

const svg = document.querySelector('#icon');

svg.style.stroke = '#2ecc71';
svg.style.fill = 'transparent';

setTimeout(() => {
  svg.style.stroke = '#9b59b6';
  svg.style.fill = '#9b59b6';
}, 800);

Такой подход часто применяется при необходимости точного тайминга относительно анимации прорисовки.


Синхронизация цвета с Vivus-анимацией

Vivus предоставляет механизм обратных вызовов, который позволяет привязывать изменения цвета к прогрессу отрисовки.

Использование onReady и onComplete

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})`;
  });
}

Цвет формируется на основе линейной интерполяции, что позволяет связать визуальную динамику с ходом прорисовки.


Использование stroke-dashoffset как триггера цвета

Поскольку Vivus управляет stroke-dashoffset, это значение может использоваться как индикатор состояния для изменения цвета через CSS-переменные.

Пример через CSS variables

.icon path {
  stroke: var(--stroke-color, #2980b9);
  transition: stroke 0.3s linear;
}
document.documentElement.style.setProperty('--stroke-color', '#8e44ad');

Изменение переменной позволяет синхронно менять цвет у всех элементов SVG без перебора DOM.


Комбинирование fill-анимации с прорисовкой контура

Типичная практика — отделение анимации обводки и заливки по времени.

Сценарий последовательного появления

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.

Линейный градиент с анимацией stop-color

<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();
}

Такой подход обеспечивает визуальную консистентность при многократных запусках.


Использование фильтров SVG для цветовой трансформации

Фильтры позволяют изменять цвет без прямого редактирования 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 от визуальных эффектов.


Интерполяция цвета через requestAnimationFrame

Для плавных переходов между цветами используется линейная интерполяция в 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-проектах строится как комбинация трёх уровней:

  • Vivus управляет прорисовкой контуров
  • CSS отвечает за базовые переходы состояний
  • JavaScript синхронизирует цветовые изменения с таймингом и логикой интерфейса

Такая архитектура позволяет разделять визуальную и поведенческую части SVG-анимации без потери контроля над финальным результатом