Stagger-анимации представляют собой последовательное применение анимационных эффектов к группе элементов с контролируемой задержкой между каждым запуском. В экосистеме Velocity.js подобный механизм является одним из ключевых инструментов построения динамичных интерфейсов, позволяя превращать массовые DOM-операции в визуально структурированные и предсказуемые последовательности.
Базовый принцип stagger-анимации заключается в том, что каждый следующий элемент в коллекции получает смещённый по времени старт относительно предыдущего. Вместо одновременного изменения состояния всех элементов формируется временная ось, на которой каждый элемент занимает собственную позицию.
В Velocity.js это достигается через параметр задержки, который интерпретируется не как фиксированная пауза, а как функция распределения времени между элементами.
Основная форма применения:
Velocity(elements, {
opacity: 1,
translateY: "0px"
}, {
duration: 400,
stagger: 100
});
Каждый элемент из коллекции elements стартует с
интервалом 100 миллисекунд относительно предыдущего.
Stagger не ограничивается линейным распределением. Поведение задержек может быть описано функцией:
t(i) = t0 + i * Δ
где:
t(i) — время старта анимации элемента с индексом it0 — начальная задержкаΔ — шаг задержкиВ Velocity.js шаг может заменяться функцией, что позволяет строить нелинейные распределения:
Velocity(elements, {
scale: 1
}, {
duration: 500,
stagger: function(elements, index) {
return index * 80;
}
});
В таком варианте формируется явный контроль над временной моделью каждого элемента.
Stagger-анимации наиболее эффективно работают с массивами DOM-узлов, полученными через селекторы или коллекции:
const items = document.querySelectorAll(".item");
Velocity(items, {
opacity: 1,
translateX: "0px"
}, {
duration: 300,
stagger: 50
});
Каждый элемент коллекции обрабатывается независимо, но синхронизированно в рамках общего таймлайна.
Распределение задержек может изменять направление последовательности.
stagger: 80
Анимация идёт от первого элемента к последнему.
stagger: [80, true]
Флаг true инвертирует последовательность, начиная с
конца массива.
Центрированный подход формирует симметричную волну анимации:
Velocity(items, {
opacity: 1
}, {
duration: 400,
stagger: {
amount: 600,
from: "center"
}
});
Такой режим создаёт эффект распространения анимации от центра контейнера к краям.
При большом количестве элементов линейный stagger может растянуть
анимацию на значительное время. Для управления общей длительностью
используется параметр amount, распределяющий суммарное
время между всеми элементами:
Velocity(items, {
translateY: "0px"
}, {
duration: 300,
stagger: {
amount: 1000
}
});
Каждый элемент получает свою долю в пределах общего временного окна.
Функция сглаживания применяется как к каждому элементу, так и к распределению задержек. Это позволяет формировать нелинейные визуальные паттерны.
Velocity(items, {
opacity: 1
}, {
duration: 500,
easing: "easeOutQuad",
stagger: 70
});
При комбинировании easing и stagger возникает эффект «ускоряющейся волны», когда элементы не только стартуют с задержкой, но и изменяют скорость движения по разным кривым.
Наиболее гибкая форма реализации основывается на функции, возвращающей задержку в зависимости от индекса, позиции или внешних факторов:
Velocity(items, {
scale: 1
}, {
duration: 400,
stagger: function(elements, index, total) {
return Math.sin(index / total * Math.PI) * 120;
}
});
Такой подход формирует нелинейное распределение с максимальными задержками в середине массива и минимальными по краям.
Velocity.js поддерживает систему очередей, где stagger-анимации могут быть встроены в цепочки переходов:
Velocity(items, { opacity: 0 }, { duration: 0 });
Velocity(items, {
opacity: 1,
translateY: "0px"
}, {
duration: 300,
stagger: 60,
queue: true
});
Каждая стадия может быть частью более сложного сценария появления, исчезновения и трансформации.
При использовании stagger в сочетании с одновременными анимациями отдельных элементов важно учитывать конкуренцию свойств. Если несколько вызовов Velocity изменяют одно и то же CSS-свойство, применяется приоритет последнего вызова в очереди.
Velocity(items, { opacity: 0.5 }, { stagger: 50 });
Velocity(items, { opacity: 1 }, { stagger: 50 });
В подобных случаях итоговое состояние зависит от порядка выполнения.
При масштабировании до сотен и тысяч DOM-узлов stagger-анимации становятся чувствительными к нагрузке. Основные факторы:
Оптимизированный подход:
Velocity(items, {
translate3d: ["0px", "0px", "0px"]
}, {
duration: 250,
stagger: 20,
queue: false
});
Использование translate3d переносит вычисления в GPU,
снижая нагрузку на основной поток.
При работе с динамически добавляемыми элементами stagger требует пересчёта коллекции на момент запуска анимации. Фиксированные NodeList могут не учитывать новые элементы, поэтому предпочтительно формировать выборку непосредственно перед вызовом:
function animateList() {
const items = document.querySelectorAll(".item");
Velocity(items, {
opacity: 1
}, {
duration: 300,
stagger: 40
});
}
Stagger-анимации часто привязываются к событиям интерфейса, где важна реакция на взаимодействие без блокировки потока исполнения.
button.addEventListener("click", () => {
Velocity(items, {
scale: 1.1
}, {
duration: 200,
stagger: 30
});
});
В таком режиме формируется эффект «распространяющегося отклика» интерфейса.
Сложные интерфейсы используют несколько уровней stagger одновременно, создавая многослойные временные структуры:
Velocity(items, {
opacity: 1
}, {
duration: 300,
stagger: 40
});
Velocity(items, {
translateY: "0px"
}, {
duration: 500,
stagger: 80
});
Разные параметры задержки формируют визуальную глубину и ощущение объёма движения элементов.