Animate Elements On Scroll With Parallax Effect – locomotive-scroll

Category: Animation , Javascript , Recommended | January 15, 2026
Authorlocomotivemtl
Last UpdateJanuary 15, 2026
LicenseMIT
Views24,817 views
Animate Elements On Scroll With Parallax Effect – locomotive-scroll

locomotive-scroll is a modern JS library that applies a smooth, subtle, configurable smooth scroll & parallax scroll effect to elements when scrolled into view.

Version 5 represents a complete rewrite from previous versions. The library now uses dual Intersection Observer strategies to optimize performance. Simple viewport triggers use one observer while continuous animations like parallax use a separate RAF-based observer.

This separation reduces unnecessary computation. locomotive-scroll automatically disables parallax on touch devices to preserve native scrolling performance. Custom scroll containers are now supported alongside the default full-page scrolling mode.

Features:

  • Dual Intersection Observer Architecture: Separates simple viewport triggers from continuous RAF-based animations.
  • Lenis-powered: Built on Lenis library for smooth scrolling with configurable easing, lerp intensity, and duration controls.
  • TypeScript Support: Fully typed API with interface definitions for all configuration options and method signatures.
  • Automatic Touch Detection: Disables parallax effects on devices with touch capability to maintain native scroll performance.
  • Custom Scroll Containers: Supports both full-page scrolling and constrained container scrolling with synchronized ResizeObserver handling.
  • Zero Layout Shift: Avoids CSS transform conflicts that break layouts by using non-greedy positioning strategies.
  • Progressive Enhancement: Elements only subscribe to requestAnimationFrame when visible and actively animating.
  • Flexible Progress Tracking: Exposes scroll progress as CSS custom properties or JavaScript events for scroll-driven animations.

Use Cases:

  • Portfolio Websites with Parallax: Implement depth effects on hero sections and project showcases where background layers move at different speeds during scroll.
  • Product Landing Pages: Trigger animations and state changes when feature sections enter the viewport to create guided scrolling experiences.
  • Long-Form Editorial Content: Add scroll progress indicators and section-based animations to improve readability on article pages.
  • Interactive Storytelling: Build narrative-driven experiences where content reveals and transforms based on scroll position and velocity.

How to use it:

1. Install the package and import the LocomotiveScroll module.

# NPM
$ npm install locomotive-scroll --save
import LocomotiveScroll from 'locomotive-scroll';
@import 'locomotive-scroll/dist/locomotive-scroll.css';

2. Or load the necessary JavaScript & CSS files from the bundled folder.

<script src="bundled/locomotive-scroll.min.js"></script>
<link href="bundled/locomotive-scroll.css" rel="stylesheet" />

3. Initialize the LocomotiveScroll with default settings.

const myScroll = new LocomotiveScroll();

4. Apply the LocomotiveScroll to target elements using the data-scroll attribute:

<div data-scroll>Element To Animate</div>

5. Config the parallax scroll effect with the following data attributes:

  • data-scroll: Enable viewport detection and scroll observation on the element. Required for all scroll-based features.
  • data-scroll-speed (number): Set parallax speed relative to scroll container size. Positive values move slower than scroll. Negative values reverse direction. Example: 0.5 moves at half scroll speed. Automatically disabled on touch devices unless data-scroll-enable-touch-speed is present.
  • data-scroll-position (string): Define trigger positions for viewport detection. Format: 'element_position, viewport_position'. Values: 'start', 'middle', 'end'. Example: 'start, middle' triggers when element’s top edge reaches viewport center. Default: 'start, end'.
  • data-scroll-offset (string): Add pixel or percentage offset to trigger points. Format: 'enter_offset, leave_offset'. Example: '200, 100' triggers 200px before entry and 100px before exit. Percentages are relative to viewport height. Default: '0, 0'.
  • data-scroll-class (string): Class name to apply when element is in viewport. Default: 'is-inview'.
  • data-scroll-repeat: Allow class and events to retrigger on each viewport entry. Without this attribute, triggers fire only once.
  • data-scroll-call (string): Custom event name to dispatch when element enters or leaves viewport. Listen with window.addEventListener(eventName, handler).
  • data-scroll-css-progress: Add --progress CSS custom property to the element. Value ranges from 0 to 1 as element moves through viewport.
  • data-scroll-event-progress (string): Custom event name for progress updates. Fires continuously with progress value in event.detail.
  • data-scroll-to: Convert element into a scroll trigger. Uses href attribute for links or data-scroll-to-href for other elements. Prevents default click behavior.
  • data-scroll-to-href (string): Target selector or position for data-scroll-to action. Example: '#section-3'.
  • data-scroll-to-offset (number): Scroll padding top in pixels for data-scroll-to action. Example: 100 adds 100px offset from target.
  • data-scroll-to-duration (number): Animation duration in seconds for data-scroll-to action. Example: 2 creates a 2-second scroll animation.
  • data-scroll-ignore-fold: Prevent automatic offset adjustment for elements visible in the initial viewport. By default, in-fold elements start their progress from their initial position.
  • data-scroll-enable-touch-speed: Override the automatic parallax disabling on touch devices. Enables data-scroll-speed on mobile and tablets. Use carefully as this may impact scroll performance.
<div data-scroll
     data-scroll-speed="1">
     data-scroll-call="EVENT_NAME"
     >
     Element To Animate
</div>

6. All possible settings to config the library.

  • lenisOptions (object): Configures the underlying Lenis instance.
    • wrapper (HTMLElement|Window): The scroll container. Defaults to window.
    • content (HTMLElement): The content element. Defaults to document.documentElement.
    • lerp (number): Linear interpolation intensity (0 to 1). Defaults to 0.1.
    • duration (number): Animation duration.
    • orientation (string): ‘vertical’ or ‘horizontal’.
    • gestureOrientation (string): ‘vertical’, ‘horizontal’, or ‘both’.
    • smoothWheel (boolean): Enables smooth scrolling for mouse wheel. Defaults to true.
    • smoothTouch (boolean): Enables smooth scrolling for touch. Defaults to false.
    • wheelMultiplier (number): Multiplier for mouse wheel events.
    • touchMultiplier (number): Multiplier for touch events.
    • normalizeWheel (boolean): Normalizes wheel inputs across browsers.
    • easing (function): Custom easing function.
  • triggerRootMargin (string): Root margin for IntersectionObserver triggers. Defaults to '-1px -1px -1px -1px'.
  • rafRootMargin (string): Root margin for RAF-based updates. Defaults to '100% 100% 100% 100%'.
  • autoStart (boolean): Starts the RAF loop automatically. Defaults to true.
  • scrollCallback (function): Callback returning scroll object { scroll, limit, velocity, direction, progress }.
  • initCustomTicker (function): Callback to initialize an external ticker (like GSAP).
  • destroyCustomTicker (function): Callback to destroy the external ticker.
const myScroll = new LocomotiveScroll({
  lenisOptions: {
    // ...
  },
  // more options here
});

7. API methods.

// Stop the scroll animation loop
// Useful when pausing scroll interactions during modals or overlays
myScroll.stop();
// Resume the scroll animation loop
// Call after stopping to re-enable scroll
myScroll.start();
// Manually trigger resize recalculation
// Rarely needed since Lenis handles ResizeObserver internally
myScroll.resize();
// Destroy the Locomotive Scroll instance and remove all event listeners
// Call when unmounting components or cleaning up instances
myScroll.destroy();
// Scroll to a target element, position, or keyword
// target: HTMLElement, number (position), or string ('top', 'bottom', CSS selector)
// options: object with offset, duration, easing, immediate, lock, force, onComplete
myScroll.scrollTo(target, options);
// Add scroll observation to newly inserted DOM elements
// newContainer: HTMLElement containing new [data-scroll] elements
myScroll.addScrollElements(newContainer);
// Remove scroll observation from DOM elements about to be removed
// oldContainer: HTMLElement containing [data-scroll] elements to unobserve
myScroll.removeScrollElements(oldContainer);

8. Event handlers.

// Fired on each scroll frame when scrollCallback is configured
// Provides scroll position, velocity, direction, and progress data
scroll = new LocomotiveScroll({
  scrollCallback: ({ scroll, limit, velocity, direction, progress }) => {
    console.log('Scroll data:', { scroll, limit, velocity, direction, progress });
  }
});
// Custom viewport trigger event (configured via data-scroll-call attribute)
// Fired when element enters or leaves viewport
window.addEventListener('yourCustomEvent', (e) => {
  const { target, way, from } = e.detail;
  // target: the element that triggered the event
  // way: 'enter' or 'leave'
  // from: 'start' or 'end' (which edge triggered)
  console.log(`Element ${way} viewport from ${from}`);
});
// Custom progress event (configured via data-scroll-event-progress attribute)
// Fired continuously as element moves through viewport
window.addEventListener('yourProgressEvent', (e) => {
  const { target, progress } = e.detail;
  // progress: 0 to 1 representing element's position in viewport
  console.log(`Element progress: ${progress}`);
});

Alternatives:

FAQs:

Q: Does it work on mobile devices?
A: Yes. However, the library automatically disables the parallax effect (data-scroll-speed) on touch devices. This preserves the native scroll feel and performance. You can force it on by adding the data-scroll-enable-touch-speed attribute.

Q: Can I use it with React or Vue?
A: Yes. You should initialize the instance inside a useEffect (React) or onMounted (Vue) hook. Remember to call .destroy() in the cleanup function to prevent memory leaks.

Q: How do I handle dynamic content loaded via AJAX?
A: You must tell the instance about the new content. Use the addScrollElements($container) method after the new DOM elements are injected.

Q: Why isn’t my fixed header working?
A: Version 5 supports position: fixed natively because it no longer uses a transform wrapper for the whole page. If you use a custom container, verify your CSS context.

Changelog:

v5.0.1 (01/15/2026)

  • Version 5 is a complete rewrite of Locomotive Scroll, now built on top of Lenis.
  • Updated doc

v4.1.4 (05/03/2022)

  • Prevent keyboard scrolling depending on activeElement type

v4.1.3 (10/21/2021)

  • Fix scrollbar locks after scrolling with mousewheel.

v4.1.0 (02/19/2021)

  • Update

v4.0.3 (11/17/2020)

  • Update

v4.0.1 (11/16/2020)

  • Add horizontal scrolling
  • Update export to only import the native Class
  • Update scrollTo parameters with the options object (offset, duration, easing…)
  • Add context system to set specific options for desktop , tablet and mobile separately
  • Rewrite the instance options
  • Add data-scroll-id=”” attribute to select elements
  • Add currents “in view” elements as object in the on scroll event.
  • Add a progress value from 0 to 1, while the element is in the viewport

v3.6.1 (10/15/2020)

  • Fix moveScrollBar calculations

v3.5.0 (05/28/2020)

  • Add scrollFromAnywhere option
  • Add multiplier option
  • Rename inertia option to lerp
  • Bugs fixed

v3.1.8 (11/30/2019)

  • Fix safari polyfill

You Might Be Interested In:


One thought on “Animate Elements On Scroll With Parallax Effect – locomotive-scroll

  1. Singh Visuals

    I know Html and Css, but I’m totally new to javascript. I don’t know where to add step 3.
    Any help?

    Reply

Leave a Reply