В Motion One групповая анимация строится вокруг идеи распределённого старта анимаций между элементами коллекции. Вместо синхронного запуска применяется смещение времени начала, формирующее каскадный эффект.
Ключевая характеристика такого подхода — управление не отдельным элементом, а набором элементов как единым контекстом, где каждый следующий участник получает индивидуальную задержку относительно базового времени старта.
Основной инструмент для создания последовательных задержек — функция
stagger.
Она формирует зависимость задержки от позиции элемента в коллекции:
import { animate, stagger } from "motion";
animate(
".item",
{ opacity: [0, 1], transform: ["translateY(20px)", "translateY(0px)"] },
{ delay: stagger(0.1) }
);
В этом примере каждый следующий элемент получает дополнительную задержку 0.1 секунды относительно предыдущего.
Математически поведение можно представить как:
[ delay_i = i step]
где:
i — индекс элементаstep — базовый шаг задержкиПомимо линейного увеличения задержки, Motion One позволяет управлять порядком обхода коллекции.
animate(
".item",
{ opacity: [0, 1] },
{ delay: stagger(0.08, { from: "last" }) }
);
В этом случае анимация начинается с последнего элемента, а первый получает максимальную задержку.
Подход “от центра” формирует радиальный эффект:
animate(
".item",
{ scale: [0.8, 1] },
{ delay: stagger(0.05, { from: "center" }) }
);
Такой режим полезен для сеток, где важна визуальная симметрия появления.
Первый аргумент stagger определяет шаг между
элементами.
stagger(0.03)
stagger(0.1)
stagger(0.2)
Меньшие значения создают плотную последовательность, большие — выраженный каскад.
Важно учитывать плотность DOM-структуры: при большом количестве элементов чрезмерный шаг задержки приводит к визуальной “разорванности” анимации.
Задержка может комбинироваться с общим стартовым смещением:
animate(
".item",
{ opacity: [0, 1] },
{
delay: stagger(0.05, { start: 0.3 })
}
);
Здесь:
start задаёт глобальную паузу перед началом всей
группыstagger добавляет локальные смещения внутри группыКомбинация этих параметров позволяет строить сложные временные структуры без ручного расчёта каждого элемента.
В случаях, когда требуется более сложная логика, delay
может быть функцией:
animate(
".item",
{ opacity: [0, 1] },
{
delay: (element, index) => {
return index * 0.06;
}
}
);
Функциональный подход позволяет учитывать:
Пример с условием:
delay: (el, i) => {
return el.dataset.priority === "high" ? 0 : i * 0.05;
}
Групповые задержки часто применяются совместно с изменением нескольких свойств:
animate(
".card",
{
opacity: [0, 1],
transform: ["translateY(30px) scale(0.95)", "translateY(0px) scale(1)"]
},
{
delay: stagger(0.07)
}
);
При этом каждый элемент проходит одинаковую траекторию, но с временным сдвигом.
При использовании keyframes задержка влияет только на старт всей последовательности, не нарушая внутреннюю структуру анимации:
animate(
".dot",
{
y: [20, -10, 0],
opacity: [0, 1, 1]
},
{
duration: 0.6,
delay: stagger(0.04)
}
);
Каждый элемент проходит полный цикл keyframes независимо, но в разное время.
При изменении DOM структура задержек пересчитывается на момент запуска анимации.
const items = document.querySelectorAll(".item");
animate(
items,
{ opacity: [0, 1] },
{ delay: stagger(0.05) }
);
Если элементы добавляются динамически, порядок задержек определяется
актуальным состоянием NodeList в момент вызова animate.
Хотя stagger по умолчанию работает как линейная функция индекса, визуально он часто применяется к сеткам.
Типичный эффект “волны” достигается комбинированием направления и шага:
animate(
".grid-item",
{ scale: [0.6, 1] },
{ delay: stagger(0.03, { from: "center" }) }
);
Для плотных сеток уменьшение шага задержки критично для предотвращения визуального отставания крайних элементов.
При большом количестве элементов важно учитывать суммарную длительность каскада:
Если:
то последний элемент начнёт анимацию через 5 секунд после первого запуска.
Для оптимизации применяются:
Разные группы элементов могут иметь независимые временные структуры:
animate(
".header-item",
{ opacity: [0, 1] },
{ delay: stagger(0.1) }
);
animate(
".content-item",
{ opacity: [0, 1] },
{ delay: stagger(0.03, { from: "last" }) }
);
Такая схема позволяет формировать многослойные сценарии появления интерфейса, где визуальная иерархия задаётся исключительно временными параметрами.