Реализация Locomotive Scroll / Lenis для плавного скролла

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация Locomotive Scroll / Lenis для плавного скролла
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация Locomotive Scroll / Lenis для плавного скролла

Locomotive Scroll и Lenis — две библиотеки, которые реализуют «масляный» скролл: скроллится не страница, а происходит интерполяция между текущей и целевой позицией. Результат — кинематографическое движение, которое можно синхронизировать с GSAP ScrollTrigger.

Выбор между ними: Lenis проще, легче, активно поддерживается (Darkroom/Studio Freight). Locomotive Scroll v2 тяжелее, но имеет встроенный parallax через data-speed. Для новых проектов Lenis — предпочтительный выбор.

Lenis: базовая установка

npm install lenis
import Lenis from 'lenis'

const lenis = new Lenis({
  duration: 1.2,           // длительность одного "шага" скролла
  easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),  // expo out
  orientation: 'vertical',
  gestureOrientation: 'vertical',
  smoothWheel: true,
  touchMultiplier: 2,      // чувствительность на тач
  infinite: false,
})

// RAF loop — Lenis требует вызова raf() каждый кадр
function raf(time: number) {
  lenis.raf(time)
  requestAnimationFrame(raf)
}

requestAnimationFrame(raf)

Интеграция Lenis + GSAP ScrollTrigger

Это основной кейс использования: Lenis управляет скроллом, ScrollTrigger — анимациями привязанными к позиции.

import Lenis from 'lenis'
import gsap from 'gsap'
import ScrollTrigger from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)

const lenis = new Lenis()

// Критично: без этого ScrollTrigger будет работать по нативному scrollY,
// а не по виртуальному скроллу Lenis
lenis.on('scroll', ScrollTrigger.update)

gsap.ticker.add((time) => {
  lenis.raf(time * 1000)  // gsap ticker даёт время в секундах
})

gsap.ticker.lagSmoothing(0)  // отключить lag smoothing GSAP

// Теперь ScrollTrigger работает корректно с Lenis
gsap.to('.hero-title', {
  scrollTrigger: {
    trigger: '.hero',
    start: 'top top',
    end: 'bottom top',
    scrub: 1,
  },
  y: -100,
  opacity: 0,
})

Parallax через Lenis

Lenis сам по себе не делает parallax — только плавный скролл. Parallax-эффекты строятся поверх через ScrollTrigger или кастомный RAF:

// Parallax без GSAP — через прямое обновление transform
const parallaxItems = document.querySelectorAll<HTMLElement>('[data-parallax]')

lenis.on('scroll', ({ scroll }) => {
  parallaxItems.forEach((el) => {
    const speed = parseFloat(el.dataset.parallax || '0.3')
    const rect = el.getBoundingClientRect()
    const center = rect.top + rect.height / 2 - window.innerHeight / 2
    el.style.transform = `translateY(${center * speed}px)`
  })
})

Locomotive Scroll v2

npm install locomotive-scroll
import LocomotiveScroll from 'locomotive-scroll'
import 'locomotive-scroll/dist/locomotive-scroll.css'

const scroll = new LocomotiveScroll({
  el: document.querySelector('[data-scroll-container]') as HTMLElement,
  smooth: true,
  multiplier: 1,
  lerp: 0.08,          // коэффициент интерполяции (чем меньше — тем плавнее)
  smartphone: {
    smooth: false,     // отключить на мобилке (нативный скролл)
  },
  tablet: {
    smooth: false,
  },
})

// Необходимо вызывать при изменении высоты контента
scroll.update()

HTML-структура для Locomotive:

<main data-scroll-container>
  <section data-scroll-section>
    <h1 data-scroll data-scroll-speed="2">Заголовок</h1>

    <!-- Sticky элемент -->
    <div data-scroll data-scroll-sticky data-scroll-target="#section">
      Sticky sidebar
    </div>

    <!-- Параллакс изображение -->
    <img
      data-scroll
      data-scroll-speed="-1"
      data-scroll-position="top"
      src="photo.jpg"
    />
  </section>
</main>

React-интеграция Lenis

import { useEffect, useRef } from 'react'
import Lenis from 'lenis'

// Singleton через React context
import { createContext, useContext } from 'react'

const LenisContext = createContext<Lenis | null>(null)

export function LenisProvider({ children }: { children: React.ReactNode }) {
  const lenisRef = useRef<Lenis | null>(null)

  useEffect(() => {
    const lenis = new Lenis({
      duration: 1.2,
      easing: (t) => Math.min(1, 1.001 - 2 ** (-10 * t)),
    })

    lenisRef.current = lenis

    let rafId: number
    function raf(time: number) {
      lenis.raf(time)
      rafId = requestAnimationFrame(raf)
    }
    rafId = requestAnimationFrame(raf)

    return () => {
      cancelAnimationFrame(rafId)
      lenis.destroy()
    }
  }, [])

  return (
    <LenisContext.Provider value={lenisRef.current}>
      {children}
    </LenisContext.Provider>
  )
}

export function useLenis() {
  return useContext(LenisContext)
}

// Программная прокрутка из любого компонента
function NavLink({ href }: { href: string }) {
  const lenis = useLenis()

  const handleClick = (e: React.MouseEvent) => {
    e.preventDefault()
    const target = document.querySelector(href)
    if (target && lenis) {
      lenis.scrollTo(target as HTMLElement, {
        offset: -80,
        duration: 1.5,
      })
    }
  }

  return <a href={href} onClick={handleClick}>...</a>
}

Остановка/возобновление скролла

Нужно для модальных окон, меню-оверлеев:

// Lenis
lenis.stop()  // заблокировать скролл
lenis.start() // разблокировать

// Locomotive Scroll
scroll.stop()
scroll.start()

Производительность и pitfalls

ResizeObserver — оба решения отслеживают высоту контента через ResizeObserver. При динамической загрузке контента (lazy images, аккордеоны) нужно вызывать lenis.resize() или scroll.update() после изменений.

iOS Safari — на iOS нативный scroll имеет особую физику (bounce). Lenis с smoothTouch: false (по умолчанию) оставляет тач-скролл нативным, что правильно.

Вложенные скроллируемые контейнеры — модалки, сайдбары со своим overflow. Нужно останавливать Lenis при входе в такой контейнер.

will-change: transform на parallax-элементах — переводит их на отдельный compositor layer, снижает перерасчёт layout.

Сроки

Lenis с базовым скроллом и ScrollTrigger анимациями — 1 день. Locomotive Scroll с parallax-данными, мобильным fallback и интеграцией в React-проект — 2–3 дня.