Функция scroll в Motion One предназначена для создания
анимаций, зависящих от положения прокрутки страницы или конкретного
контейнера. Она связывает значение скролла с вычисляемыми прогрессами,
позволяя строить интерфейсы, реагирующие на движение документа без
ручной работы с событиями scroll и без постоянного
перерасчёта координат.
В основе лежит идея реактивного отслеживания прокрутки: библиотека преобразует текущее положение скролла в нормализованное значение, обычно в диапазоне от 0 до 1, и передаёт его в пользовательский обработчик или систему анимаций.
Функция scroll подписывается на изменения прокрутки и
вычисляет прогресс движения относительно заданного диапазона.
import { scroll } from "motion";
scroll((progress) => {
// progress: значение от 0 до 1
});
Значение progress отражает относительное положение
скролла между начальной и конечной точками. Это позволяет строить
анимации, не привязываясь к пиксельным значениям.
Помимо простого прогресса, scroll может предоставлять
объект состояния, содержащий несколько координатных значений:
scroll(({ y, x }) => {
// y — вертикальная прокрутка
// x — горизонтальная прокрутка
});
Такой подход позволяет одновременно отслеживать оба направления, что важно для сложных интерфейсов с горизонтальными лентами, каруселями и комбинированной навигацией.
Прокрутка может быть ограничена одной осью. В большинстве случаев используется вертикальная ось, однако горизонтальные сценарии также поддерживаются.
scroll(({ y }) => {
const progress = y.progress;
});
Типичная структура данных оси включает:
Это позволяет отделить физическое движение страницы от логики анимации.
scroll может работать не только с окном браузера, но и с
любым прокручиваемым контейнером. Это важно для интерфейсов с
внутренними областями прокрутки.
const container = document.querySelector(".scroll-container");
scroll((progress) => {
// обработка прогресса
}, {
container
});
В этом режиме расчёты выполняются относительно границ указанного элемента, а не документа.
Контейнерный режим используется в:
Вместо глобального скролла может использоваться привязка к конкретному элементу, когда прогресс вычисляется относительно его появления в области видимости.
const element = document.querySelector(".section");
scroll((progress) => {
// прогресс появления элемента
}, {
target: element
});
В этом режиме прогресс обычно интерпретируется как:
Одной из ключевых возможностей является управление диапазоном
вычисления прогресса с помощью offset.
scroll((progress) => {
// прогресс ограничен заданными границами
}, {
target: element,
offset: ["start end", "end start"]
});
Offset определяет, какие точки элемента и viewport считаются началом и концом анимации.
Распространённые логики:
animateГлавная ценность scroll проявляется при связке с
функцией animate, где прокрутка напрямую управляет
параметрами анимации.
import { scroll, animate } from "motion";
scroll((progress) => {
animate(".box", {
opacity: progress,
transform: `scale(${0.5 + progress * 0.5})`
});
});
В реальных сценариях такая связка заменяется более оптимизированными паттернами, где анимация создаётся один раз, а скролл лишь обновляет её прогресс.
Прокрутка может рассматриваться как аналог временной шкалы анимации. Вместо времени используется позиция пользователя на странице.
scroll((progress) => {
// прогресс фактически заменяет time
});
Такой подход позволяет создавать:
Одно из наиболее частых применений scroll —
параллакс.
scroll((progress) => {
const y = progress * 200;
document.querySelector(".background").style.transform =
`translateY(${y}px)`;
});
При этом фон движется медленнее или быстрее основного контента, создавая ощущение глубины.
При сложных интерфейсах несколько элементов могут реагировать на один и тот же прогресс.
scroll((progress) => {
const offset1 = progress * 100;
const offset2 = progress * 300;
layer1.style.transform = `translateY(${offset1}px)`;
layer2.style.transform = `translateY(${offset2}px)`;
});
Каждый слой получает собственную функцию преобразования прогресса, что позволяет строить многослойные сцены.
scroll работает через оптимизированный цикл обновления,
синхронизированный с requestAnimationFrame. Это снижает
нагрузку по сравнению с прямым использованием события
scroll.
Ключевые особенности:
Подписка, создаваемая scroll, возвращает функцию
остановки наблюдения.
const stop = scroll((progress) => {
// логика
});
stop();
Это позволяет:
При работе с горизонтальными интерфейсами scroll
адаптируется к оси X.
scroll(({ x }) => {
const progress = x.progress;
});
Применения:
В сложных интерфейсах может использоваться одновременное отслеживание обеих осей.
scroll(({ x, y }) => {
const px = x.progress;
const py = y.progress;
});
Такой подход используется в:
Сценарий появления элементов при прокрутке реализуется через отслеживание прогресса входа в viewport.
scroll((progress) => {
element.style.opacity = progress;
element.style.transform = `translateY(${(1 - progress) * 50}px)`;
}, {
target: element
});
Элемент постепенно появляется при приближении к зоне видимости.
На основе scroll строятся типовые архитектуры
интерфейсов:
Внутри Motion One прокрутка фактически превращается в координатную систему, где:
Это позволяет рассматривать интерфейс как непрерывное пространство, а не набор отдельных событий.
scroll может выступать центральным управляющим
механизмом для нескольких независимых анимаций.
scroll((progress) => {
animate(".title", { opacity: progress });
animate(".image", { scale: 0.8 + progress * 0.2 });
animate(".text", { y: (1 - progress) * 20 });
});
Каждый элемент получает свою интерпретацию одного и того же значения прогресса, что обеспечивает согласованность поведения интерфейса.
При резких изменениях прокрутки система обновлений сглаживает переходы, чтобы исключить визуальные рывки. Это особенно важно для мобильных устройств, где частота событий скролла нестабильна.
Функция scroll выступает связующим звеном между:
Она переводит физическое движение страницы в управляемый поток числовых значений, который используется как универсальный источник данных для визуальных изменений.