Locomotive Scroll — это библиотека для создания плавного скроллинга с эффектами параллакса и анимаций. При использовании Server-side rendering (SSR) возникают специфические нюансы, связанные с тем, что библиотека тесно взаимодействует с DOM. Поскольку на сервере DOM отсутствует, необходимо учитывать моменты инициализации и условного рендера скриптов.
Отсутствие объекта window и
document на сервере Locomotive Scroll напрямую
обращается к window и document. При рендеринге
на сервере это вызывает ошибки:
const scroll = new LocomotiveScroll({
el: document.querySelector('#scroll-container'),
smooth: true
});
На сервере document не существует, что приведёт к
падению сборки.
Необходимость условной инициализации Для
корректной работы при SSR нужно проверять наличие
window:
let scroll;
if (typeof window !== 'undefined') {
const LocomotiveScroll = require('locomotive-scroll').default;
scroll = new LocomotiveScroll({
el: document.querySelector('#scroll-container'),
smooth: true
});
}
Этот приём гарантирует, что скрипт будет выполняться только в браузере.
Пререндеринг контента и расчёт размеров Locomotive Scroll рассчитывает размеры элементов при инициализации. На сервере это невозможно. При SSR рекомендуется:
update():scroll.update();При использовании Next.js или других фреймворков с SSR ключевым является разделение серверного и клиентского кода.
Пример с использованием React hooks:
import { useEffect, useRef } from 'react';
import LocomotiveScroll from 'locomotive-scroll';
import 'locomotive-scroll/dist/locomotive-scroll.css';
export default function SmoothScrollContainer({ children }) {
const scrollRef = useRef(null);
useEffect(() => {
const scroll = new LocomotiveScroll({
el: scrollRef.current,
smooth: true,
multiplier: 1.2
});
return () => scroll.destroy();
}, []);
return (
{children}
);
}
useEffect гарантирует выполнение кода
только на клиенте, после того как DOM готов.ref используется для безопасного
доступа к элементу контейнера.destroy() предотвращает утечки памяти при
размонтировании компонента.Если на странице динамически меняется контент (например, при загрузке данных с API), важно пересчитывать скролл:
useEffect(() => {
if (scrollRef.current) {
scrollRef.current.update();
}
}, [dynamicContent]);
update() сообщает Locomotive Scroll о новых элементах и
их позициях.update() после каждого изменения DOM,
которое влияет на размеры контейнера.Атрибуты data-scroll и
data-scroll-speed Их можно рендерить на сервере,
так как это обычные HTML-атрибуты. Анимации будут работать только на
клиенте после инициализации Locomotive Scroll.
Позиционирование элементов Locomotive Scroll
использует transform: translate3d(...). При SSR элементы
остаются в исходных позициях до монтирования на клиенте. Важно учитывать
визуальные смещения при первом рендере страницы, чтобы избежать
“скачков” контента.
Locomotive Scroll можно интегрировать с GSAP, Framer Motion или другими библиотеками. При SSR:
useLayoutEffect или
componentDidMount для синхронизации с DOM.Пример с GSAP:
useEffect(() => {
const scroll = new LocomotiveScroll({ el: scrollRef.current, smooth: true });
gsap.from('.animate', {
scrollTrigger: {
scroller: scrollRef.current,
trigger: '.animate',
start: 'top 80%',
end: 'bottom 20%',
scrub: true
},
y: 50,
opacity: 0
});
return () => scroll.destroy();
}, []);
scroller указывает на контейнер Locomotive Scroll.ref и useEffect для
безопасной работы с элементами.data-scroll безопасно рендерить на
сервере, они будут активны после монтирования.destroy()
предотвращает утечки памяти и некорректное поведение при смене
страниц.update()
только при необходимости.resize и scroll.