Parallax: Scroll Effects

Linton Ye





This module makes it easy to create advanced scroll interactions. There are two ways of using the module:

  • Non-coding: just drag and drop components, you’ll be able to move layers at different speed when scrolling.
  • Code overrides: a lot more control and flexibility (see below)

Check out some quick demos:

Demo file:

Getting started

  • Non-coding:
    1. Just drop a few “Parallax Layer” and connect them with respective content.
    2. Drop a “Parallax Scroll” and connect with the entire scroll content.
    3. Tweak the “Speed X” and “Speed Y” parameters and profit!
  • Code overrides:
    1. Add a Scroll and connect to its scrolling content. Yes, you can just use the standard Scroll component!
    2. Create a code override file that uses scrollOverrides to define custom scrolling behaviors. See below for examples.
    3. Add the code override to Scroll and other items.
    4. Profit!

Properties for Non-coding usage

Parallax Layer

  • Input: Speed or Position
    • Speed
      • Pin in scrolling direction
        • if true and the direction of parent Parallax is vertical, the Y position of the layer remains the same when scrolling. It works similarly when the parent direction is horizontal.
      • Speed X
        • if 0: the layer scrolls along with the rest of the content
        • if positive: the layer scrolls in the same direction as the scrolling
        • if negative: the layer scrolls in the opposite direction of the scrolling
      • Speed Y
        • Same as Speed X but in Y direction
    • Position
      • X: an expression that specifies the X position of the layer
        • Can be a math formula where s is the scroll position
        • Examples:
          • 0: the layer scrolls along with the rest of the content
          • -s: this is equivalent to Pin in scrolling direction when Input is Speed
          • sin(s/50)*100: moves the layer left and then right and then left again, repeatedly
      • Y: Same as X but in Y direction

Code overrides

A simple example: make an item sticky


import {
} from "@framer/lintonye.parallax/code/Parallax";

// Define custom scrolling behavior
const overrides = scrollOverrides(
  [100, 200],  // scrolling range
  { id: "sticky100200", op: sticky() } // custom behavior

// Define code overrides
//   1. There will always be a "overrides.scroll" function
//   2. Note "overrides.sticky100200" comes from the "id" above
//   3. Don't forget to call the functions and pass along the "props" parameter.
export const Scroll : Override = props => overrides.scroll(props);
export const Sticky100200 : Override = props => overrides.sticky100200(props);

Make an item sticky and then fades away

sticky and fade

const overrides = scrollOverrides(
  [100, 200], 
  { id: "sticky100200", op: sticky() },
  [200, 500], 
  { id: "sticky100200", op: modulate('opacity', [1, 0]) }

Move an item move at a different speed


const overrides = scrollOverrides(
  [0, 1000], 
    { id: "speed0", op: speed(0) },
    { id: "speed05", op: speed(0.5) },
    { id: "speedminus1", op: speed(-1) },
    { id: "speedminus2", op: speed(-2) },
    { id: "speed1", op: speed(1) }

Trigger an animation when scrolling into a range


const overrides = scrollOverrides(
  [600, 650],
    // This function will only be executed once per direction when
    // the scrolling position falls into the range specified above.
    // i.e. scrolling down, it'll be called, but if keep scrolling down,
    // it won't be called anymore. But if scrolling up at this point,
    // it'll be called again.
    // Don't forget the "getData =>" in the front!
    op: getData => ({ vy }) => {
      // vy: the velocity of scrolling in y direction
      //   vy > 0: scrolling down
      //   vy < 0: scrolling up
      animate.spring(data.rotation, vy > 0 ? 180 : 0);


Find me on Twitter @lintonye!

Change Log

  • 02/21/2019
    • Hide internal components
  • 02/03/2019
    • Add support for using object as op, instead of just an array
    • Fixed: onMove op function is always called when a data item is updated inside the function body
    • Now we can return true to ask the next onMove op function to run. If the return value is falsy (e.g. no return value is specified), the function will be only called once per scroll direction.
  • 01/29/2019
    • Fix id conflict issue. Now, as long as the ids are unique within a single scrollOverrides call, things should be fine.
  • 01/26/2019
    • Add support for horizontal scroll. Note: you’ll get an error when the scroll direction is “both”.
    • Add speed, sticky and snap functions, which work on both horizontal and vertical directions.
  • 01/23/2019
    • Fix issue in speed and sticky that causes layer to jump locations when crossing ranges
  • 01/17/2019
    • Add snapY function
  • 01/16/2019
    • Add support for advanced scroll interactions
  • 01/10/2019
    • Add override functions for sticky scrolls (Doc pending)
  • 10/09/2018
    • Support controlling positions with math expressions
  • 10/08/2018
    • Better performance - (dev note: no more cloning of children)
  • 10/07/2018
    • Better scrolling performance
    • We can now independently configure speed X and Y of a layer.
    • Pin in scroll direction
  • 10/02/2018 - Support horizontal scroll
  • 09/18/2018 - Use Scroll component instead of the hacky div


  • Version: 1.39.0
  • Updated: 6 months ago
  • License: MIT


By using our website, you agree to the use of cookies as described in our  Privacy Policy —
I Agree