Stagger-эффект представляет собой технику анимации, при которой однотипные элементы запускают переходы с небольшими задержками относительно друг друга. Вместо одновременного старта анимации для всей группы создаётся последовательность, формирующая ритм, направленность движения и визуальную иерархию.
В контексте DOM-анимаций stagger применяется к массивам элементов: спискам, сеткам, карточкам интерфейса, таблицам, меню. Основная идея заключается в вычислении задержки старта анимации на основе позиции элемента в наборе.
Motion One предоставляет встроенную поддержку stagger через функцию
stagger(), интегрированную в систему animate()
и timeline().
Функция stagger() возвращает функцию расчёта задержки
для каждого элемента коллекции.
import { animate, stagger } from "motion";
animate(
".item",
{ opacity: [0, 1], transform: ["translateY(20px)", "none"] },
{ delay: stagger(0.1) }
);
В этом примере:
.item получает индивидуальную
задержкуМеханизм работает через индекс элемента в коллекции:
delay = index * interval
Stagger поддерживает изменение направления распределения задержек.
animate(
".item",
{ opacity: [0, 1] },
{ delay: stagger(0.08, { from: "last" }) }
);
Параметр from определяет точку начала:
"first" — стандартный порядок"last" — обратный порядок"center" — распространение от центраПри работе с сетками или симметричными интерфейсами используется распространение от центра:
animate(
".card",
{ scale: [0.8, 1], opacity: [0, 1] },
{ delay: stagger(0.05, { from: "center" }) }
);
Поведение зависит от индексации элементов: центральные запускаются первыми, крайние — последними, формируя радиальный эффект.
Timeline позволяет комбинировать stagger с последовательными и параллельными анимациями.
import { timeline, stagger } from "motion";
timeline([
[".header", { opacity: [0, 1] }, { duration: 0.4 }],
[
".item",
{ y: [30, 0], opacity: [0, 1] },
{ delay: stagger(0.06) }
],
[".footer", { opacity: [0, 1] }, { duration: 0.3 }]
]);
Stagger внутри timeline действует локально для текущего шага и не влияет на другие сегменты.
Задержка может вычисляться через пользовательскую функцию, что позволяет реализовать сложные зависимости:
animate(
".tile",
{ opacity: [0, 1] },
{
delay: (i, total) => {
return (total - i) * 0.03;
}
}
);
Параметры функции:
i — индекс элементаtotal — общее количество элементовТакой подход позволяет реализовать:
Для сеточных структур применяется расчёт на основе координат, а не линейного индекса.
const items = document.querySelectorAll(".grid-item");
animate(
items,
{ opacity: [0, 1], scale: [0.9, 1] },
{
delay: stagger(0.04, {
from: [2, 2]
})
}
);
Значение from в виде массива интерпретируется как
координаты точки распространения. Это создаёт эффект «вспышки» или
«волны» от заданной позиции.
Stagger управляет только временем старта, в то время как easing и keyframes формируют характер движения.
animate(
".dot",
{
y: [50, 0],
opacity: [0, 1]
},
{
delay: stagger(0.03),
easing: "ease-out",
duration: 0.6
}
);
Каждый элемент получает одинаковую кривую движения, но стартует с собственной задержкой.
При сложной композиции возможно наложение нескольких stagger-паттернов через разные селекторы.
animate(".row-1 .cell", {
opacity: [0, 1]
}, { delay: stagger(0.02) });
animate(".row-2 .cell", {
opacity: [0, 1]
}, { delay: stagger(0.02, { from: "last" }) });
Так создаётся контраст направлений между группами элементов.
Stagger одинаково применяется для появления и исчезновения элементов.
animate(
".menu-item",
{ opacity: [1, 0], x: [0, -10] },
{ delay: stagger(0.05, { from: "last" }) }
);
Обратный порядок усиливает эффект «сворачивания» интерфейса.
Интервал stagger может быть адаптирован под количество элементов. При большом числе узлов применяется уменьшение шага:
const items = document.querySelectorAll(".list-item");
animate(
items,
{ opacity: [0, 1] },
{
delay: stagger(0.2 / items.length)
}
);
Так сохраняется одинаковая общая длительность анимации независимо от размера списка.
В интерфейсах с несколькими слоями применяется каскадное распределение:
import { animate, stagger } from "motion";
animate(".title", { opacity: [0, 1] }, { duration: 0.4 });
animate(".subtitle", { opacity: [0, 1] }, { delay: 0.2 });
animate(".card", {
opacity: [0, 1],
y: [20, 0]
}, {
delay: stagger(0.05)
});
Комбинация последовательных и stagger-анимаций формирует многоуровневую динамику интерфейса.
Stagger в Motion One работает без промежуточных таймеров на каждый элемент. Все задержки вычисляются заранее и передаются в единый план анимации.
Это снижает нагрузку на:
Особенно заметно при больших списках (100+ элементов), где
альтернативные подходы с setTimeout приводят к деградации
производительности.
from интерпретируются относительно текущего
набора элементовStagger часто используется вместе с вычисляемыми трансформациями:
animate(
".box",
(i) => ({
transform: [
`translateY(${i * 2}px) scale(${1 - i * 0.02})`,
"none"
]
}),
{
delay: stagger(0.04)
}
);
Индекс элемента становится параметром геометрии анимации, усиливая глубину композиции.