Анимации, привязанные к прокрутке, основаны на связи между положением скролла и параметрами визуального состояния элемента. Вместо дискретного запуска анимации по событию применяется непрерывное преобразование значений:
Ключевое отличие от классических CSS-анимаций — отсутствие фиксированных таймингов. Движение становится функцией прокрутки, а не времени.
В экосистеме веб-анимаций Motion One предоставляет минималистичный
API для построения таких эффектов без необходимости вручную работать с
scrollTop, requestAnimationFrame и сложными
вычислениями прогресса.
Любая scroll-анимация сводится к преобразованию диапазона:
scrollY: 0 → 1000
progress: 0 → 1
style: начальное → конечное состояние
Пример логики:
Motion One абстрагирует эту модель через функцию
scroll().
Основной инструмент для привязки анимации к прокрутке —
scroll().
Она позволяет:
import { scroll, animate } from "motion";
scroll(
animate(".box", {
opacity: [0, 1],
transform: ["translateY(50px)", "translateY(0px)"]
})
);
Здесь:
scroll() управляет прогрессомanimate() описывает изменение свойств.box изменяется в зависимости от положения
страницыScroll-анимации могут быть связаны не только с окном браузера, но и с конкретным контейнером.
scroll(
animate(".card", {
scale: [0.8, 1],
opacity: [0.2, 1]
}),
{
target: document.querySelector(".container")
}
);
В этом случае:
.containerЧасто анимация строится вокруг изменения transform-значений:
Пример эффекта появления карточек:
scroll(
animate(".item", {
opacity: [0, 1],
transform: ["translateY(80px)", "translateY(0px)"]
})
);
Такой подход позволяет создавать:
Важный аспект scroll-анимации — ограничение диапазона триггера.
В Motion One можно задавать точки начала и конца анимации.
scroll(
animate(".hero", {
opacity: [1, 0],
scale: [1, 1.2]
}),
{
offset: ["start start", "end start"]
}
);
start start — начало элемента совпадает с началом
viewportend start — конец элемента достигает начала
viewportТаким образом формируется зона прогресса.
Комбинация timeline и scroll позволяет строить сложные сцены.
import { scroll, timeline } from "motion";
scroll(
timeline([
[".title", { opacity: [0, 1], y: [40, 0] }],
[".subtitle", { opacity: [0, 1], y: [40, 0] }, { at: "-0.3" }],
[".button", { opacity: [0, 1], scale: [0.9, 1] }, { at: "-0.2" }]
])
);
Особенности:
Параллакс — эффект разной скорости движения слоёв.
scroll(
animate(".background", {
transform: ["translateY(0px)", "translateY(-200px)"]
})
);
scroll(
animate(".foreground", {
transform: ["translateY(0px)", "translateY(-50px)"]
})
);
Результат:
Motion One позволяет синхронизировать такие эффекты без ручного вычисления скорости.
Scroll-анимации могут быть слишком «резкими», если не учитывать плавность изменения прогресса.
Встроенные механизмы позволяют:
Пример:
scroll(
animate(".panel", {
rotate: [0, 10]
}),
{
offset: ["start end", "end start"]
}
);
При этом движение не скачет, а интерполируется между состояниями.
Хотя scroll() управляет прогрессом, часто используется
inView для первичной активации.
import { inView, animate } from "motion";
inView(".section", () => {
animate(".section", {
opacity: [0, 1],
transform: ["translateY(60px)", "translateY(0px)"]
});
});
Комбинация подходов:
Motion One поддерживает смешанные сценарии, где элемент сначала появляется, а затем продолжает реагировать на прокрутку.
Один scroll-поток может управлять множеством анимаций:
const animation = animate(".box", {
opacity: [0, 1],
scale: [0.8, 1]
});
scroll(animation);
scroll(animate(".text", {
opacity: [0, 1],
y: [30, 0]
}));
Так создаётся единый визуальный сценарий, где:
Scroll-анимации чувствительны к производительности. Основные принципы:
Motion One оптимизирован для работы через
requestAnimationFrame, что снижает нагрузку на основной
поток.
В подходе Motion One важна умеренность: scroll должен усиливать интерфейс, а не подменять его поведение.