Функция stagger

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

В Motion One функция stagger позволяет распределять старт анимации по элементам массива с заданным интервалом, создавая эффект каскада.


Базовая идея stagger

При анимации коллекции элементов каждому элементу назначается одинаковая анимация, но с индивидуальной задержкой.

Логика проста:

  • первый элемент начинает сразу
  • каждый следующий стартует через фиксированный интервал времени

Это формирует визуальную волну.


Синтаксис stagger

stagger(delay, options?)

Параметры

delay (number) Базовая задержка между элементами в миллисекундах.

options (object) — необязательный параметр:

  • startDelay — общая задержка перед стартом всей группы
  • from — точка отсчёта (индекс элемента, центр, конец или конкретное число)
  • ease — функция распределения задержек

Простейший пример использования

import { animate, stagger } from "motion";

animate(
  ".item",
  { opacity: [0, 1], transform: ["translateY(20px)", "translateY(0)"] },
  { delay: stagger(100) }
);

Каждый элемент .item будет появляться с задержкой 100 мс относительно предыдущего.


stagger и массив DOM-элементов

Motion One автоматически применяет stagger ко всем элементам, подходящим под селектор.

Эквивалентная логика:

const items = document.querySelectorAll(".item");

items.forEach((el, i) => {
  animate(
    el,
    { opacity: [0, 1] },
    { delay: i * 100 }
  );
});

Но stagger заменяет эту ручную арифметику более декларативной формой.


Параметр startDelay

startDelay задаёт задержку перед запуском всей группы.

animate(
  ".card",
  { opacity: [0, 1], y: [20, 0] },
  { delay: stagger(80, { startDelay: 500 }) }
);

В этом случае:

  • сначала ждёт 500 мс
  • затем запускает каскадную анимацию

Управление направлением: from

Параметр from определяет, с какого элемента начинается распределение задержек.

from: “first” (по умолчанию)

stagger(100, { from: "first" });

Анимация идёт сверху вниз или слева направо — в порядке DOM.


from: “last”

stagger(100, { from: "last" });

Эффект обратного каскада: последний элемент стартует первым.

Используется для:

  • закрывающихся меню
  • исчезающих списков снизу вверх

from: “center”

stagger(100, { from: "center" });

Анимация начинается из центра списка и расходится в обе стороны.

Часто применяется в:

  • сетках карточек
  • модальных окнах
  • галереях

from: number

stagger(100, { from: 2 });

Задаёт конкретный индекс, от которого начинается распространение.

Это даёт точный контроль над визуальным акцентом.


ease внутри stagger

ease управляет распределением задержек, а не самой анимацией.

Линейное распределение

stagger(100, { ease: "linear" });

Каждый элемент получает равномерную задержку.


Нелинейное распределение

stagger(100, { ease: "easeOut" });

Элементы ближе к начальной точке запускаются плотнее, дальше — реже.

Это создаёт более «живой» эффект волны.


stagger в сложных анимациях

stagger не ограничен простыми свойствами. Он работает с любыми анимируемыми параметрами Motion One.

Пример: комбинированная анимация

animate(
  ".box",
  {
    opacity: [0, 1],
    transform: ["scale(0.5)", "scale(1)"]
  },
  {
    delay: stagger(60, { from: "center" }),
    duration: 0.6
  }
);

Элементы появляются и масштабируются с центровой волной.


stagger и transform-эффекты

Наиболее выразительные результаты достигаются при комбинировании stagger с transform-свойствами.

Снизу вверх

animate(
  ".item",
  {
    opacity: [0, 1],
    y: [30, 0]
  },
  {
    delay: stagger(80)
  }
);

Раскрытие из центра

animate(
  ".tile",
  {
    opacity: [0, 1],
    scale: [0.8, 1]
  },
  {
    delay: stagger(50, { from: "center" })
  }
);

Диагональная динамика (через DOM-порядок)

animate(
  ".cell",
  {
    opacity: [0, 1],
    rotate: [-10, 0]
  },
  {
    delay: stagger(40, { ease: "easeInOut" })
  }
);

Влияние количества элементов

stagger автоматически масштабируется под размер коллекции.

Если элементов мало — эффект почти незаметен. Если элементов много — возникает выраженная волна.

Это важно учитывать:

  • 3–5 элементов: минимальный эффект
  • 10–20 элементов: оптимальный визуальный баланс
  • 50+ элементов: выраженная кинетика движения

stagger и динамические списки

При изменении DOM (например, фильтрации списка) stagger пересчитывается заново при повторном вызове animate.

function animateList() {
  animate(
    ".list-item",
    { opacity: [0, 1], x: [-10, 0] },
    { delay: stagger(70) }
  );
}

Каждый новый рендер создаёт новый каскад.


Сочетание stagger с keyframes

Motion One позволяет использовать keyframes внутри stagger-анимации.

animate(
  ".dot",
  {
    y: [0, -10, 0],
    opacity: [0, 1, 0]
  },
  {
    delay: stagger(50)
  }
);

Каждый элемент проходит одинаковый путь, но в разное время.


stagger в обратных сценариях UI

stagger используется не только для появления, но и для исчезновения.

Исчезновение списка

animate(
  ".item",
  { opacity: [1, 0], y: [0, 20] },
  { delay: stagger(60, { from: "last" }) }
);

Элементы исчезают снизу вверх.


Производительность stagger

stagger не создаёт отдельных таймеров для каждого элемента. Вместо этого используется вычисление задержки на основе индекса.

Это делает его:

  • предсказуемым
  • лёгким для браузера
  • стабильным при больших списках

Типичные ошибки при использовании stagger

Слишком маленький delay

stagger(5)

Эффект теряется, элементы воспринимаются как почти одновременные.


Слишком большой delay

stagger(500)

Анимация становится разорванной и медленной.


Игнорирование from

Отсутствие from в сложных сетках приводит к визуальной неструктурированности.


Комбинации stagger с layout-анимациями

При работе с изменяемыми интерфейсами stagger часто комбинируется с изменением позиции элементов.

animate(
  ".card",
  {
    opacity: [0, 1],
    scale: [0.9, 1]
  },
  {
    delay: stagger(80, { from: "center" })
  }
);

Такие эффекты часто используются в:

  • фильтруемых галереях
  • списках товаров
  • дашбордах

stagger как инструмент композиции движения

stagger не является просто задержкой. Он формирует структуру восприятия движения.

Через него можно задавать:

  • направление появления
  • центр визуального внимания
  • ритм интерфейса
  • плотность визуального потока

В интерфейсной анимации stagger выступает как базовый механизм организации групповой динамики элементов.