Scroll animations come in three kinds: blocks that reveal as they enter the viewport, motion tied to the scroll position, and video whose frames follow the scroll forwards and backwards. A good scroll animation moves only transform and opacity, plays a reveal once, and switches off for anyone who has turned on "reduce motion" in their system. If the text can't be read without the animation, or visitors have to "scroll through" an effect to reach the contact button, that's a mistake, not a technique.
After this you will be able to
- Tell apart the three families of scroll animation: reveal on enter, scroll-linked motion and scrub video
- Choose an implementation: IntersectionObserver, CSS scroll-driven animations behind @supports, or one update per frame with requestAnimationFrame
- Explain why every frame is made a keyframe for scrub video
- Plan a prefers-reduced-motion fallback and identify screens where scroll animation does not belong
Contents
Three families of scroll animation
The micro-interactions lesson covered why an interface needs motion at all. This one is only about scrolling. "Scroll animation" actually hides three different mechanisms: they're built differently, load a phone differently and need different fallbacks.
- 01Reveal on enterA block enters the viewport and a short animation plays once. Scrolling only triggers it.
- 02Scroll-linkedThe scroll position becomes a timeline: scroll halfway and the animation is halfway through, in both directions.
- 03Scrub videoA special case of scroll-linking: scrolling moves the frames of a video forwards and backwards instead of CSS properties.
Reveal on enter
- What drives it
- The fact that a block became visible
- Where it fits
- Almost any site: cards, case studies, testimonials
- Main risk
- Long delays — the text lags behind the reader
Scroll-linked
- What drives it
- The scroll position
- Where it fits
- Reading progress, sticky scenes, product stories
- Main risk
- Load on the phone, motion sickness, hijacked scrolling
Scrub video
- What drives it
- Scroll position turned into video time
- Where it fits
- One flagship screen that shows how something is built
- Main risk
- A heavy file and stutter if encoded the wrong way
Revealing blocks as they enter the viewport
The most common and the safest kind. A block starts slightly transparent and shifted down a little, and when it enters the viewport it eases into place. This used to mean recalculating element positions on every scroll event — expensive. Today the standard tool is IntersectionObserver: the browser asynchronously reports that an element has crossed the edge of the viewport, so you don't have to listen to every pixel of scrolling (MDN covers it in detail).
Blocks appear as you scroll
- Play it once: stop observing the element after it appears, and don't hide it again when scrolling back up
- Keep the offset small and the motion short — a reveal mustn't hold up reading
- Trigger slightly before the block is fully in view so people never stare at empty space
- Content is visible without JavaScript: if the script fails to load, blocks must not stay transparent
When a row holds several cards, it's handy to show them as a cascade (stagger): each one starts with a small delay after the previous one. A cascade hints at the reading order and makes the grid feel alive. But with a long delay the last card arrives so late that people scroll past it.
All at once
Staggered, 60 ms step
Animation linked to scrolling
In the second family, scrolling isn't a start button but a playhead. Scroll a third of the way and the animation is a third of the way through; scroll back and it rewinds. That's how a reading-progress bar above an article works, a header that shrinks as you scroll, and sticky scenes: a section pins to the screen with position: sticky, and while the visitor scrolls, the steps of a story change inside it.
For a long time this could only be done with scripts that calculated progress and changed styles on every scroll event. CSS now has native scroll-driven animations: the animation-timeline property ties an ordinary CSS animation to a container's scroll timeline (scroll()) or to how a particular element travels through the viewport (view()). Chrome for Developers points out that these animations can run off the main thread — so they stay smooth even when the page is busy with other work.
Reading progress
A bar above the article fills as you scroll. The simplest and most useful example: people can see how much is left.
Sticky scene
A section pins in place while the image and caption change step by step. Good for a short "how it works" story.
Reveal along the way
An element fades in as it passes through the viewport and fades out just as smoothly. Unlike the first family, this is reversible.
The golden rule of this family is never to hijack the scroll itself. The page should move exactly as the visitor turns the wheel or swipes: the animation follows the scroll, it doesn't replace it with its own pace.
Scrub video: frames that follow the scroll
The third family is video controlled by scrolling. The clip doesn't play on its own: the scroll position is converted into the video's time (the video element's currentTime property), so frames move forwards as you scroll down and backwards as you scroll up. It lets you take an object apart and put it back together, move a camera through a space, or show a process that's hard to explain in words.
The main technical trap is encoding. A regular video file stores a full (key) frame only occasionally, and between keyframes it stores just the changes relative to neighbouring frames. When you jump to an arbitrary point, the decoder has to go back to the nearest keyframe and rebuild everything up to the frame you want. Scrolling backwards makes this especially visible: the video stutters or freezes. So for a scrub scene the clip is re-encoded so that every frame is a keyframe — then any frame opens instantly, in both directions.
Regular encoding
- Keyframes are rare, with only differences in between
- A light file, fine for normal playback
- Jerky rewinding: the decoder goes back to a keyframe
- Suits a background video that simply plays
Every frame a keyframe
- Each frame decodes on its own
- Smooth forwards and backwards at any scroll speed
- A noticeably heavier file — weight has to be saved elsewhere
- Suits a scene driven by scrolling
- A short clip: one scene, no spare seconds at the start or end
- Moderate resolution, plus a separate lighter version for phones
- No audio track — a scrub scene doesn't need one
- Show a poster frame right away and load the clip as the section approaches the viewport
- The alternative is an image sequence on canvas: more control, but more files too
How it works in InterLAB demo projects
The InterLAB portfolio includes demo sites where we work through these mechanisms. They aren't client commissions but showcase projects — still, in each one the scroll answers a specific visitor question rather than just decorating the page.
- Krem Coffee, a coffee-shop demo: a scrub video takes the drink apart layer by layer — you see what it's made of — and reassembles it when you scroll back.
- Lumen Dental, a dental-clinic demo: scrolling drives a 3D cross-section of a veneer, so visitors see how it's built.
- Nega SPA, a spa demo: scrolling works as a camera moving through the rooms, so you can "walk through" the space before your visit.
What all three share: one unusual mechanism per page, and calm block reveals everywhere else. Prices, booking forms and contacts in these demos aren't animated, and with "reduce motion" turned on, the main scene is replaced with still frames.
Parallax and performance
Parallax means page layers moving at different speeds: the background slower, the foreground faster, creating a sense of depth. In its parallax testing, Nielsen Norman Group saw mostly unimpressed users and a familiar set of problems: pages load more slowly, text over a moving background is harder to read, and people who scroll quickly looking for something hit blank screens because the effect hasn't loaded yet. On top of that, large background movement relative to the foreground is a typical trigger of motion sickness for people with vestibular disorders.
If you do need parallax, keep it gentle: a small speed difference, decorative layers only, text on a stationary base.
- Move only transform and opacity — the browser handles them at the compositing stage without recalculating layout
- Don't read element sizes in a scroll handler interleaved with style writes — that's layout thrashing, a forced layout recalculation on every frame
- Use IntersectionObserver for reveals, and CSS scroll-driven animations or one update per frame via requestAnimationFrame for scroll-linking
- Start heavy scenes only when the section is near the viewport, and pause them once it's gone
- Test on a mid-range phone, not just the developer's laptop: that's where you see dropped frames
Accessibility and when to skip animation
Operating systems have a "reduce motion" setting, and a site can detect it through the prefers-reduced-motion media query (documented on MDN and web.dev). WCAG success criterion 2.3.3, Animation from Interactions, asks that motion triggered by user interaction — and scrolling is an interaction — can be disabled unless it's essential. For scroll animations that means: with the setting on, parallax and scroll-linked scenes switch off, blocks appear with a simple fade or instantly, and a scrub video is replaced by a still frame or a captioned series of images.
Fits
- A product promo page and a "how it's built" story
- The flagship section of a case study or home page
- A reading-progress bar in a long article
- Gentle reveals of cards and testimonials
Skip it
- Prices and plans — people are comparing and need a still table
- Contact and payment forms — nearby motion distracts and breaks focus
- Legal text: terms, policies, conditions
- Working and reference screens people return to often
The scroll belongs to the visitor. Animation can follow it, but it must never take it away.
Sources
- MDN — Intersection Observer API
- MDN — CSS scroll-driven animations
- MDN — animation-timeline
- Chrome for Developers — Animate elements on scroll with scroll-driven animations
- MDN — HTMLMediaElement: currentTime
- Nielsen Norman Group — Parallax Scrolling: Attention-Getter or Headache?
- web.dev — How to create high-performance CSS animations
- web.dev — Avoid large, complex layouts and layout thrashing
- MDN — prefers-reduced-motion
- web.dev — prefers-reduced-motion: Sometimes less movement is more
- W3C WAI — Understanding SC 2.3.3: Animation from Interactions