В библиотеке Motion One групповые анимации строятся вокруг идеи
одновременного управления набором DOM-элементов или последовательного их
запуска с контролируемыми задержками. Основная модель основана на
передаче массива элементов в функции animate, а также
использовании параметров оркестрации (delay,
stagger, at) и управления временем выполнения
через timeline.
Групповая анимация применяется в интерфейсах, где требуется синхронное поведение визуальных компонентов: списки, сетки карточек, модальные окна с вложенными элементами, сложные переходы между состояниями UI.
Базовый подход заключается в передаче коллекции DOM-узлов:
import { animate } from "motion"
const items = document.querySelectorAll(".item")
animate(
items,
{ opacity: [0, 1], transform: ["translateY(20px)", "translateY(0px)"] },
{ duration: 0.6 }
)
Каждый элемент получает одинаковую анимацию, синхронизированную по времени. При этом Motion One оптимизирует обработку коллекции, объединяя вычисления в единый поток обновления.
Несмотря на групповую передачу, каждый элемент сохраняет собственное
состояние анимации. Это позволяет впоследствии модифицировать поведение
отдельных узлов через повторный вызов animate или через
управление контроллером.
const controls = animate(items, {
opacity: 1,
transform: "none"
})
controls.pause()
controls.play()
Контроллер управляет всей группой как единым объектом, сохраняя при этом индивидуальную интерполяцию значений.
Stagger-эффект используется для создания последовательных задержек между элементами массива. Это ключевой механизм, позволяющий превращать статичную группу в динамическую последовательность.
animate(
".item",
{ opacity: [0, 1], transform: ["scale(0.8)", "scale(1)"] },
{ delay: stagger(0.1) }
)
Каждый следующий элемент начинает анимацию с задержкой 0.1 секунды относительно предыдущего.
При работе с сетками применяется зависимость задержки от позиции элемента:
animate(
".item",
{ opacity: [0, 1], transform: ["translateY(30px)", "translateY(0px)"] },
{
delay: stagger(0.05, { start: 0, from: "center" })
}
)
Параметр from задаёт точку распространения анимации:
центр, край или произвольный индекс.
stagger(0.08, { from: "last" })
Позволяет разворачивать направление группового появления, создавая эффект обратного каскада.
timeline используется для координации нескольких групп
элементов и независимых анимационных сцен.
import { timeline } from "motion"
timeline([
[".header", { opacity: [0, 1] }, { duration: 0.4 }],
[".item", { y: [30, 0], opacity: [0, 1] }, { delay: stagger(0.05) }],
[".footer", { opacity: [0, 1] }, { at: "+0.2" }]
])
Каждый шаг timeline представляет собой отдельную группу анимаций с собственной временной осью.
Параметр at позволяет задавать смещение относительно
предыдущего шага:
at: 0 — старт одновременно с началом timelineat: "+0.2" — задержка после завершения предыдущей
группыat: "<" — одновременный запуск с предыдущим
шагомМаски применяются для управления видимостью группы элементов в
процессе анимации. В контексте Motion One маски часто используются
совместно с CSS-свойствами clip-path,
mask-image и трансформациями контейнеров.
animate(
".panel",
{
clipPath: [
"inset(100% 0 0 0)",
"inset(0% 0 0 0)"
]
},
{ duration: 0.7 }
)
Контейнер выступает маской для вложенной группы, создавая эффект «раскрытия».
animate(
".list",
{ height: ["0px", "300px"] },
{ duration: 0.5 }
)
Внутренние элементы группы остаются статичными, но становятся видимыми по мере изменения контейнера.
SVG предоставляет более гибкий уровень контроля над группами через
<mask> и <clipPath>.
animate(
"#maskRect",
{ width: ["0%", "100%"] },
{ duration: 1 }
)
При изменении параметров маски изменяется видимость всей группы элементов, находящихся под ней.
timeline([
["#mask1", { width: ["0%", "100%"] }, { duration: 0.5 }],
["#mask2", { height: ["0%", "100%"] }, { at: "-0.2" }]
])
Маски могут пересекаться по времени, создавая сложные переходы между визуальными слоями.
DOM-группа часто рассматривается как единый трансформационный слой. В Motion One это достигается через анимацию родительского элемента.
animate(
".card-group",
{ scale: [0.8, 1], opacity: [0, 1] },
{ duration: 0.5 }
)
Все дочерние элементы наследуют трансформацию контейнера, что снижает вычислительную нагрузку.
animate(
".grid",
{
rotate: ["-2deg", "0deg"],
scale: [0.95, 1],
opacity: [0, 1]
},
{ duration: 0.6 }
)
Использование комбинированных свойств усиливает ощущение целостности группы.
Оркестрация определяет порядок запуска анимаций внутри и между группами.
animate(
".item",
{ x: [-20, 0], opacity: [0, 1] },
{ delay: stagger(0.08) }
)
Элементы запускаются последовательно, образуя каскад.
timeline([
[".left-column", { opacity: [0, 1] }],
[".right-column", { opacity: [0, 1] }, { at: 0 }]
])
Обе группы стартуют одновременно, но могут иметь разные внутренние stagger-параметры.
Вместо геометрических масок часто применяется имитация маскирования через прозрачность и масштабирование.
animate(
".item",
{ opacity: [0, 1], filter: ["blur(6px)", "blur(0px)"] },
{ delay: stagger(0.05) }
)
Размытие усиливает эффект появления группы как единого слоя.
animate(
".popup",
{ scale: [0.7, 1], opacity: [0, 1] },
{ duration: 0.4 }
)
Сочетание масштабирования и прозрачности создаёт иллюзию раскрытия пространства.
Группы часто формируются динамически на основе данных, особенно при рендеринге списков или виртуальных интерфейсов.
const renderItems = () => {
const items = document.querySelectorAll(".item")
animate(
items,
{ opacity: [0, 1], y: [10, 0] },
{ delay: stagger(0.03) }
)
}
Каждое обновление DOM приводит к новой анимации группы без необходимости хранения состояния предыдущих элементов.
При полной перерисовке интерфейса Motion One обрабатывает новые узлы как независимую группу, что позволяет избегать конфликтов между старыми и новыми анимациями.
Наиболее сложные сценарии возникают при наложении групповых анимаций и масок.
timeline([
[".modal", { opacity: [0, 1] }, { duration: 0.3 }],
[
".modal-content .item",
{ y: [20, 0], opacity: [0, 1] },
{ delay: stagger(0.05) }
]
])
Контейнер анимируется как маска, а вложенные элементы формируют внутреннюю структуру появления.
animate(
".card",
{
clipPath: ["inset(100% 0 0 0)", "inset(0% 0 0 0)"],
opacity: [0, 1]
},
{ delay: stagger(0.06) }
)
Каждый элемент раскрывается внутри собственной маски, создавая эффект последовательного «разворачивания» интерфейса.
Групповые операции оптимизируются через минимизацию layout-thrashing и использование transform/opacity как основных анимируемых свойств.
transform и opacitywidth,
height)animate(
".grid-item",
{ opacity: [0, 1], scale: [0.9, 1] },
{ delay: stagger(0.02, { from: "center" }) }
)
animate(
".dot",
{ scale: [0, 1], opacity: [0, 1] },
{ delay: stagger(0.03, { from: "first" }) }
)
timeline([
[".mask-left", { width: ["0%", "50%"] }],
[".mask-right", { width: ["0%", "50%"] }, { at: 0 }]
])
Группы раскрываются симметрично, формируя зеркальную композицию.
Иерархия групп формируется через вложенные контейнеры, каждый из которых имеет собственную временную ось.
Такой подход позволяет строить сложные интерфейсные сцены без необходимости ручного управления каждым DOM-элементом отдельно