Lenis

How smooth scroll should be

README

LENIS

npm version

Introduction


This is our take on smooth scroll, lightweight, hard-working, smooth as butter scroll. See Demo.



Features


- Run scroll in the main thread
- Performant
- Lightweight (<4Kb gzipped)
- Keep CSS Sticky and IntersectionObserver
- Accessibility (CMD+F page search, keyboard navigation, keep scroll position on page refresh, etc.)
- External RAF
- SSR proof
- Custom scroll easing and duration



Feature[Locomotive-scroll](https://github.com/locomotivemtl/locomotive-scroll)[GSAP[Lenis](https://github.com/studio-freight/lenis)
|-----------------------------|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
Native
Native
Normalize
Accessibility
CSS
IntsersectionObserver
Open
Built-in
Size[12.1KB](https://bundlephobia.com/package/locomotive-scroll@4.1.4)[26.08KB](https://bundlejs.com/?q=gsap%2FScrollSmoother&treeshake=%5B%7BScrollSmoother%7D%5D)[3.6KB](https://bundlephobia.com/package/@studio-freight/lenis@1.0.0-dev.8)



Installing


using a package manager:

  1. ```bash
  2. $ npm i @studio-freight/lenis
  3. ```
  1. ```js
  2. import Lenis from '@studio-freight/lenis'
  3. ```



using scripts:

  1. ```htmt
  2. <script src="https://cdn.jsdelivr.net/gh/studio-freight/lenis@1.0.0/bundled/lenis.js"></script>
  3. ```



Setup


Basic setup:

  1. ```js
  2. const lenis = new Lenis()

  3. lenis.on('scroll', (e) => {
  4.   console.log(e)
  5. })

  6. function raf(time) {
  7.   lenis.raf(time)
  8.   requestAnimationFrame(raf)
  9. }

  10. requestAnimationFrame(raf)
  11. ```




Instance settings


OptionTypeDefaultDescription
|----------------------|----------------------|----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
`wrapper``HTMLElement|Window``window`The
`content``HTMLElement``document.documentElement`The
`lerp``number``0.1`Linear
`duration``number``1.2`The
`easing``function``(t)The
`orientation``string``vertical`The
`gestureOrientation``string``vertical`The
`smoothWheel``boolean``true`Whether
`smoothTouch``boolean``false`Whether
`wheelMultiplier``number``1`The
`touchMultiplier``number``2`The
`normalizeWheel``boolean``true`Normalize
`infinite``boolean``false`Enable



<!-- target: goal to reach
- number: value to scroll in pixels
- string: CSS selector or keyword (top, left, start, bottom, right, end)
- HTMLElement: DOM element



options:
- offset(number): equivalent to [scroll-padding-top](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-padding-top)
- lerp(number): animation lerp intensity
- duration(number): animation duration (in seconds)
- easing(function): animation easing
- immediate(boolean): ignore duration, easing and lerp
- lock(boolean): whether or not to prevent user from scrolling until target reached
- onComplete(function): called when target is reached -->

Instance Methods


MethodDescriptionArguments
|-----------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
`raf(time)`Must`time`:
`scrollTo(target,Scroll`target`:
`on(id,`id`|
`stop()`Pauses|
`start()`Resumes|
`destroy()`Destroys|

Instance Events


EventCallback
|----------|--------------------|
`scroll`Lenis



Considerations


Make sure scroll-behavior is set to auto or not set at all


  1. ```css
  2. .lenis.lenis-smooth {
  3.   scroll-behavior: auto;
  4. }
  5. ```

Keep HTML elements default sized, this is necessary for Webflow implementation (see issue)


  1. ```css
  2. html.lenis {
  3.   height: auto;
  4. }
  5. ```

Use the data-lenis-prevent attribute on nested scroll elements. In addition, we advise you to add overscroll-behavior: contain on this element


  1. ```html
  2. <div data-lenis-prevent>scroll content</div>
  3. ```

  1. ```css
  2. .lenis.lenis-smooth [data-lenis-prevent] {
  3.   overscroll-behavior: contain;
  4. }
  5. ```

Manually use lenis.scrollTo('#anchor') on anchor link click (see issue)


  1. ```html
  2. <a href="#anchor" onclick="lenis.scrollTo('#anchor')">scroll to anchor</a>
  3. ```

Hide overflow when lenis is stopped

  1. ```css
  2. .lenis.lenis-stopped {
  3.   overflow: hidden;
  4. }
  5. ```

GSAP ScrollTrigger integration

  1. ```js
  2. lenis.on('scroll', ScrollTrigger.update)

  3. gsap.ticker.add((time)=>{
  4.   lenis.raf(time * 1000)
  5. })
  6. ```



Limitations


- no support for CSS scroll-snap
- capped to 60fps on Safari (source)
- smooth scroll will stop working over iframe since they don't forward wheel events
- position fixed seems to lag on MacOS Safari pre-M1 (source)



Tutorials







Plugins





Lenis in use





Authors


This set of hooks is curated and maintained by the Studio Freight Darkroom team:

- Clément Roche (@clementroche\_) – Studio Freight
- Guido Fier (@uido15) – Studio Freight
- Leandro Soengas (@lsoengas) - Studio Freight
- Franco Arza (@arzafran) - Studio Freight



License