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 }}/>
#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.