Motion
Back to framer.com
DocumentationAnimation
Scroll
Motion
Back to framer.com
Design and publish your first free site today.
Getting started
  • Introduction
  • Examples
Animation
  • Overview
  • Layout
  • Gestures
  • Scroll
  • Transition
Components
  • motion
  • AnimatePresence
  • LayoutGroup
  • LazyMotion
  • MotionConfig
  • Reorder
Motion values
  • Overview
  • useMotionValueEvent
  • useMotionTemplate
  • useScroll
  • useSpring
  • useTime
  • useTransform
  • useVelocity
  • useWillChange
Hooks
  • useAnimate
  • useAnimationFrame
  • useDragControls
  • useInView
  • useReducedMotion
Universal
  • animate
  • transform
  • stagger
  • Easing functions
3D
  • Introduction
  • LayoutCamera
  • LayoutOrthographicCamera
  • MotionCanvas
Guides
  • Accessibility
  • Reduce bundle size
  • Upgrade guides
Community
  • GitHub
  • Discord

Scroll animations

How to create scroll-linked and scroll-triggered animations in Framer Motion.

There are two predominant types of scroll animations, both of which can be achieved with Framer Motion.

Scroll-linked animations are when the progress of an animation is directly tied to scroll progress. Scroll-triggered animations are when a normal animation is triggered when an element enters or leaves the viewport.

#Scroll-linked animations

Scroll-linked animations are created using motion values and the useScroll hook.

import { motion, useScroll } from "framer-motion"
function Component() {
const { scrollYProgress } = useScroll();
return (
<motion.div style={{ scaleX: scrollYProgress }} />
)
}

Read the full useScroll docs to discover how to track element scroll, element positions within the viewport, create parallax effects and more.

#No-code

The easiest API is no API, and that's why Framer Motion is used to create the scroll-linked animations in Framer, the web builder for creative pros.

You can create animations in seconds, with no code, using the Scroll Transforms feature.

Remix the demo site to get started in seconds.

#Scroll-triggered animations

Scroll-triggered animations are normal animations that start when an element enters or leaves the viewport.

The whileInView prop can be used to create scroll-triggered animations by defining a set of properties and, optionally, a transition, to animate to when the element is in view.

<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
/>

Note: There's currently a bug in Chrome where IntersectionObserver doesn't work correctly with SVG elements.

#Props

#whileInView: VariantLabels | TargetAndTransition

Properties or variant label to animate to while the element is in view.

<motion.div whileInView={{ opacity: 1 }} />

#viewport: ViewportOptions

An object of viewport options that define how the viewport is detected.

<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
/>

#onViewportEnter(entry): void

Callback that triggers when the element enters the viewport. Provides the IntersectionObserverEntry with details of the intersection event, or null if the browser doesn't support IntersectionObserver.

#onViewportLeave(entry): void

Callback that triggers when the element leaves the viewport. Provides the IntersectionObserverEntry with details of the intersection event. Will never be called if the browser doesn't support IntersectionObserver.

#Viewport options

#once: boolean

If true, once the element has entered the viewport it will remain in the whileInView state. No further viewport callbacks will be triggered.

<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
/>

#root: RefObject<Element>

By default, the element will be considered within the viewport when it enters the window viewport.

Pass a ref to both an ancestor element and to viewport.root to use that ancestor element as the measured viewport instead.

function Component() {
const scrollRef = useRef(null)
return (
<div ref={scrollRef} style={{ overflow: "scroll" }}>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ root: scrollRef }}
/>
</div>
)
}

#margin: string

A margin to add to the viewport when detecting whether the element has entered it.

Defaults to "0px". A single value can be used to add a margin on every side, e.g. "200px". Or, multiple values can be defined to assign a margin to each axis in the order of top/right/bottom/left, e.g. "0px -20px 0px 100px".

#amount: "some" | "all" | number

Defaults to "some", this option defines the amount of the element that has to intersect with the viewport in order for it to be considered within view.

#No-code

It's also possible to create scroll-triggered animations in Framer with zero code.

Remix the demo site to get started in seconds.

#Examples

#Page scroll progress

#Spring smoothing

#Element scroll progress

#Track element position

#Parallax

#3D

#Scroll velocity

PreviousGesturesNextTransition
On this page
  • Scroll-linked animations
  • No-code
  • Scroll-triggered animations
  • Props
  • Viewport options
  • No-code
  • Examples
  • Page scroll progress
  • Spring smoothing
  • Element scroll progress
  • Track element position
  • Parallax
  • 3D
  • Scroll velocity

Copyright © 2022 Framer B.V.

  • Security
  • Terms of Service
  • Privacy Statement