ScrollMagic — это библиотека JavaScript, позволяющая создавать
анимации и эффекты на основе прокрутки страницы. Она изначально
ориентирована на работу в браузере, что создаёт определённые трудности
при использовании в средах с серверным рендерингом (SSR, Server-Side
Rendering), таких как Next.js или Nuxt.js. Основная проблема заключается
в том, что ScrollMagic оперирует объектами браузера
(window, document), которые на сервере
недоступны.
Для корректной интеграции необходимо учитывать условное подключение и инициализацию ScrollMagic только в клиентской среде.
if (typeof window !== 'undefined') {
const ScrollMagic = require('scrollmagic');
const controller = new ScrollMagic.Controller();
}
Это гарантирует, что сервер не будет пытаться выполнять код, зависящий от DOM.
Контроллер (ScrollMagic.Controller) — это центральный
объект, управляющий всеми сценами (ScrollMagic.Scene). При
использовании SSR важно создавать контроллер только на
клиенте, после того как DOM полностью доступен:
useEffect(() => {
const controller = new ScrollMagic.Controller();
return () => controller.destroy(true);
}, []);
Здесь используется хук useEffect для React или
аналогичные события mounted в Vue, чтобы гарантировать
выполнение кода на клиенте.
Сцена (ScrollMagic.Scene) связывает конкретный элемент с
анимацией. Для SSR подход остаётся прежним: создание сцены должно
происходить только после того, как элемент доступен в DOM.
useEffect(() => {
if (typeof window === 'undefined') return;
const controller = new ScrollMagic.Controller();
const scene = new ScrollMagic.Scene({
triggerElement: '#animateMe',
duration: 300,
offset: 50
})
.setClassToggle('#animateMe', 'visible')
.addTo(controller);
return () => {
scene.destroy(true);
controller.destroy(true);
};
}, []);
Ключевые моменты:
triggerElement должен существовать на момент создания
сцены.duration задаёт протяжённость анимации по скроллу.offset позволяет сдвинуть начало триггера относительно
элемента.ScrollMagic часто используется вместе с библиотекой анимаций GSAP
(gsap). В SSR-контексте важно убедиться, что анимации
создаются после рендера DOM:
useEffect(() => {
if (typeof window === 'undefined') return;
const controller = new ScrollMagic.Controller();
const tween = gsap.to("#animateMe", { duration: 1, x: 300, opacity: 1 });
const scene = new ScrollMagic.Scene({
triggerElement: "#animateMe",
duration: 500
})
.setTween(tween)
.addTo(controller);
return () => {
scene.destroy(true);
controller.destroy(true);
};
}, []);
Это позволяет плавно интегрировать ScrollMagic с любыми анимациями без ошибок на сервере.
Наиболее частые ошибки при SSR связаны с попыткой доступа к
window или document на сервере. Чтобы их
избежать:
Проверка окружения:
const isClient = typeof window !== 'undefined';Динамический импорт ScrollMagic: В Next.js можно использовать:
import dynamic from 'next/dynamic';
const ScrollMagic = dynamic(() => import('scrollmagic'), { ssr: false });Инициализация внутри useEffect или
mounted: гарантирует доступ к DOM и предотвращает
ошибки рендера.
При использовании ScrollMagic на больших страницах важно учитывать нагрузку на скролл-обработчики:
tweenChanges: true для плавных анимаций
без постоянного пересчёта.Пример очистки ресурсов:
useEffect(() => {
if (!isClient) return;
const controller = new ScrollMagic.Controller();
const scene = new ScrollMagic.Scene({ triggerElement: '#animateMe' })
.setClassToggle('#animateMe', 'visible')
.addTo(controller);
return () => {
scene.destroy(true);
controller.destroy(true);
};
}, []);
Next.js: динамический импорт и использование
useEffect предотвращают ошибки рендера.
Nuxt.js: сцены создаются в mounted,
контроллер уничтожается в beforeDestroy.
Gatsby: проверка
typeof window !== 'undefined' перед использованием
ScrollMagic предотвращает ошибки на этапе сборки.