The wrong question is whether CSS Scroll-Driven Animations can replace GSAP ScrollTrigger.
The useful question is how much control the interaction actually needs.
If scroll only needs to map progress to presentation: grow a progress bar, shift an image, reveal a heading, change scale as an element crosses the viewport, start with CSS. The browser now has a native vocabulary for that job.
If scroll needs to conduct a sequence: pin a scene, coordinate several elements, snap between chapters, fire call-backs, react to direction, or drive a larger animation timeline, ScrollTrigger gives you a control surface CSS is not trying to be.
And sometimes the correct answer is neither. position: sticky, a static composition, Intersection Observer, or one small transition may communicate the idea with less machinery.
Here is the useful rule:
CSS is strongest when scroll is the timeline. ScrollTrigger is strongest when scroll controls a timeline.Interaction jobCSS Scroll-Driven AnimationsGSAP ScrollTriggerReading progressExcellent fitUsually unnecessarySimple parallaxExcellent fitExcellent fitView-linked revealExcellent fitExcellent fitCoordinated multi-step sequenceComplexity rises quicklyStrong fitPinned storytellingNative layout can helpStrong fitTimeline snappingLimitedStrong fitScroll call-backsNeeds JavaScriptBuilt inDirection or velocity logicNeeds JavaScriptBuilt inApplication-state coordinationNeeds JavaScriptStrong fitProgressive visual enhancementStrong fitRequires deliberate fallbackRich React runtime controlLimited by designStrong fit, with lifecycle costThe interesting part is where that boundary moves in production.
See the Same Interaction Built Both Ways
Start with a simple reveal. An image enters slightly lower and transparent, then settles into place as it moves through the viewport.
This should be a boring architecture decision.
The CSS version
Make the static, readable state the default. Then enable the animation only when the relevant scroll-driven properties are supported.
.reveal {
opacity: 1;
transform: none;
}
@keyframes reveal {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@supports (
(animation-timeline: view()) and
(animation-range: entry 10% cover 40%)
) {
.reveal {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 10% cover 40%;
}
}
view() creates a view-progress timeline based on where the element sits inside its scrollport. animation-range narrows the portion of that timeline used by the animation.
MDN documents scroll- and view-progress timelines as part of CSS Scroll-Driven Animations.
The fallback is intentional: if the browser does not support the required features, the element remains visible in its normal position. Nothing essential waits for animation support.
The same reveal with ScrollTrigger
gsap.fromTo(
".reveal",
{
y: 40,
autoAlpha: 0,
},
{
y: 0,
autoAlpha: 1,
ease: "none",
scrollTrigger: {
trigger: ".reveal",
start: "top 90%",
end: "top 60%",
scrub: true,
},
}
);
ScrollTrigger handles the same job cleanly. Its scrub option connects animation progress to scroll progress.
But nothing here needs pinning, call-backs, snapping, a multi-stage timeline, or application state. If this were the full brief, native CSS has a strong architectural argument because the problem already fits its model.
Now change the brief.
Keep a product image fixed for two viewport heights. Reveal three claims in sequence. Rotate the product between chapters. Snap toward the nearest stage when scrolling stops. Update another piece of UI when chapter three becomes active.
It is still a “scroll animation.”
It is no longer the same problem.
Where CSS Scroll-Driven Animations Fit Best
Traditional CSS animation normally progresses with time. Scroll-Driven Animations allow CSS keyframes to progress against a scroll-progress or view-progress timeline instead.
With animation-timeline: scroll(), progress can follow a scroll container. With view(), it can follow a subject as that element moves through the scrollport. Named timelines are available when the relationship needs to be more explicit.
That makes CSS particularly attractive when the interaction has a simple answer to this sentence:
At this scroll position, the visual state should be here.
Think progress indicators, restrained parallax, image scaling, masks, opacity changes, text reveals, background shifts, and similar presentation-level effects.
The implementation stays close to the styles it controls. There is no animation-specific React lifecycle to manage, no ScrollTrigger instance to clean up, and no JavaScript call-back whose only job is converting scroll progress into a visual value.
That does not mean CSS is automatically faster.
It means CSS now models this class of problem directly.
Where ScrollTrigger Starts to Earn Its Place
ScrollTrigger becomes more useful when progress alone is not enough.
Its current API supports scrubbing, pinning, snapping, call-backs, and integration with GSAP timelines. It also exposes runtime information including progress, direction, and velocity.
Consider a pinned product story.
The scene remains fixed while the reader moves through several chapters. The first reveals an interface. The second rotates the product and changes the supporting copy. The third exposes a detail view. Several transitions overlap rather than moving through one simple linear interpolation.
The interaction is structurally a timeline:
const timeline = gsap.timeline({
scrollTrigger: {
trigger: ".product-story",
start: "top top",
end: "+=200%",
scrub: true,
pin: true,
},
});
timeline
.to(".product-model", { rotate: 12 })
.to(".feature-one", { autoAlpha: 1 }, "<")
.to(".product-model", { scale: 1.08 })
.to(".feature-two", { autoAlpha: 1 }, "<0.2");
You can reproduce pieces of this with CSS Scroll-Driven Animations and position: sticky. Sometimes that remains the cleaner implementation.
But once you need deliberate stages, coordinated overlap, pin-duration management, call-backs, snapping, or state outside CSS, avoiding a timeline system can become the more complicated choice.
The test is not “Can CSS technically do this?”
It is which implementation keeps the interaction understandable when the page changes later?
CSS vs ScrollTrigger: The Production Decision
QuestionStart with CSS when…Start with ScrollTrigger when…What drives the effect?Progress maps directly to visual propertiesProgress controls a broader sequenceHow many moving parts?A few elements have clear statesSeveral elements need coordinated choreographyDoes content stay pinned?position: sticky solves the layout clearlyPinning belongs to a larger controlled sequenceDo you need call-backs?No runtime behaviour depends on animation stateEnter/update/leave logic mattersDo you need snapping?Native scroll behaviour is enoughTimeline stages need controlled snappingDoes direction matter?Current progress is sufficientBehaviour changes by direction or velocityIs application state involved?NoYesCan the effect disappear safely?Static fallback preserves the experienceThe interaction needs a deliberate alternate pathIs it inside React?Styling can remain mostly declarativeRuntime control justifies lifecycle managementThere is no scorecard where one call-back automatically means GSAP or one CSS declaration automatically means “simpler.”
Choose based on the shape of the interaction.
Performance: Stop Comparing Logos
“CSS is fast; JavaScript is slow” is not a useful performance model.
Animation cost depends on what changes, how many elements participate, whether layout and paint are involved, how much measurement happens, what else runs on the page, and whether expensive work continues when the interaction is no longer relevant.
Property choice matters regardless of tool. Transform and opacity are often appropriate for frequent visual changes because they can avoid some layout work, but large layers, filters, excessive DOM volume, and compositing pressure still have costs.
Complex scroll stories also introduce measurement. Fonts load. Images alter dimensions. Responsive layouts change trigger positions. Pinned sections change page geometry.
So profile the finished page.
Not just the isolated animation.
Test a production build with the navigation, media, analytics, and other interactions running. Test real mobile hardware. Clean up runtime animations and listeners when components disappear.
Current Vault scroll guidance takes the same approach: real-device testing, cleanup, readable DOM content, and simpler mobile fallbacks belong to production implementation rather than post-launch polish.
Performance is an implementation property, not a CSS or GSAP personality trait.
Browser Support Can Decide the CSS Route Early
Native does not mean universal.
As of September 2026, MDN still marks both animation-timeline and animation-range as Limited availability rather than Baseline because they do not work across all widely used browsers.
That does not make them unusable.
It makes fallback quality part of the architecture.
For a decorative reveal, falling back to the static final state can be perfectly acceptable. The content remains intact and the page still communicates.
For a product walkthrough where essential information appears only at specific points in a scroll sequence, losing the animation may also mean losing content. That needs an alternative layout, not simply a missing animation.
Progressive enhancement works when the enhancement is genuinely optional.
Browser support is moving quickly enough that compatibility should be checked again when the page ships rather than frozen into a permanent rule from an article.
React and Next.js Change the Cost of ScrollTrigger
CSS Scroll-Driven Animations can often stay presentation-level. React renders the content; CSS describes how presentation responds to scrolling.
ScrollTrigger adds runtime behaviour, so React needs to own that lifecycle correctly.
For the React helper used below, install GSAP and its React package:
npm install gsap @gsap/react
GSAP's useGSAP() hook wraps its context system so animations and ScrollTriggers created inside the hook can be cleaned up when the component unmounts. Scoped selector strings apply to descendants of the scope element.
A minimal Next.js client component can look like this:
"use client";
import { useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";
gsap.registerPlugin(ScrollTrigger, useGSAP);
export function ProductStory() {
const root = useRef<HTMLElement>(null);
useGSAP(
() => {
gsap
.timeline({
scrollTrigger: {
trigger: root.current,
start: "top top",
end: "+=200%",
scrub: true,
pin: true,
},
})
.to(".product", { rotate: 12 })
.to(".detail", { autoAlpha: 1 }, "<");
},
{ scope: root }
);
return (
<section ref={root}>
<div className="product" />
<div className="detail">Feature detail</div>
</section>
);
}
The scope handles descendant selectors such as .product and .detail; the ScrollTrigger itself targets root.current directly. GSAP's React guidance notes that scoped selector text is limited to descendants of the scope element.
The larger architectural point matters more than the hook syntax. Browser-dependent animation logic needs an appropriate client boundary, deliberate scoping, and cleanup. Runtime control is useful when the interaction needs it; otherwise, that lifecycle is extra machinery.
Reduced Motion and Mobile Should Change the Interaction
Desktop scroll sequences can consume enormous amounts of space: long pins, horizontal tracks, perspective movement, deep parallax.
A phone does not need to preserve all of that.
A pinned horizontal sequence may become a vertical stack. A scrubbed spatial transition may become a static image progression. A large parallax treatment may use less travel or disappear.
Reduced motion deserves the same architectural treatment.
Keep content in logical DOM order. Do not make essential copy dependent on reaching a precise scroll position. Keep links and controls usable when pinning or scrubbing is removed. When motion is reduced, hierarchy and meaning should survive even if the choreography does not.
Current Vault guidance similarly recommends collapsing complex pinned, horizontal, or perspective behaviour into vertical sections, native swipe, or static cards where that better suits mobile.
The technology changes. The responsibility does not.
Can CSS Scroll Timelines and ScrollTrigger Live Together?
Yes, if they do different jobs.
A sensible hybrid might let CSS own a reading-progress indicator and small view-linked reveals while ScrollTrigger owns one complex pinned sequence.
The important thing is ownership.
Do not casually let CSS and GSAP animate the same property on the same element. Active CSS keyframe animations have a defined place in the cascade that outranks normal author declarations, including normal inline declarations, so this is not a simple “whichever wrote last wins” contest.
More importantly, split ownership makes the interaction difficult to understand even when the browser result is predictable.
Separate responsibility by property or, better, by component.
Hybrid should remove complexity.
Not hide it.
Where Hyperiux Vault Fits
Vault sits above this tool decision.
Its scroll catalogue provides editable React and Next.js interaction patterns while dependencies remain specific to the individual effect rather than forcing every pattern through one animation engine. Current Vault surfaces show scroll patterns using GSAP, Lenis, Motion, and other effect-specific dependencies.
The same decision rule still applies after you find a ready-made pattern.
A small reveal may be cleaner natively. A composed pinned sequence may justify ScrollTrigger. Source-first code gives you an implementation to inspect and adapt; it does not remove the need to evaluate mobile behaviour, reduced motion, dependencies, and the page around it.
Browse Hyperiux Vault Scroll Effects
The Decision
Use CSS Scroll-Driven Animations when scroll mostly maps progress to presentation and a static or simplified fallback preserves the experience.
Use GSAP ScrollTrigger when scroll needs to orchestrate a sequence: pinning, coordinated timelines, snapping, call-backs, runtime state, direction, or richer control.
Use both when separate interactions have separate responsibilities and the ownership boundary stays obvious.
Use neither when motion adds more machinery than meaning.
Before shipping, ask:
- Does scroll simply control visual progress, or is it conducting a sequence?
- Would the page still work if the animation disappeared?
- Do I genuinely need pinning, snapping, call-backs, or runtime state?
- What happens in a browser without the required CSS features?
- What does this interaction become on mobile and under reduced motion?
Have I tested the finished page rather than only the animation?
CSS Scroll-Driven Animations give the platform a much stronger native answer to scroll-linked motion.
ScrollTrigger remains useful because sophisticated scroll experiences eventually stop being interpolation problems and become orchestration problems.
Know which problem you have.
Then use the smaller machine that solves it.
Frequently Asked Questions
Can CSS Scroll-Driven Animations replace GSAP ScrollTrigger?
For some interactions, yes. Simple scroll-progress and view-progress effects can be expressed directly in CSS. ScrollTrigger adds runtime control for work such as pinning, coordinated timelines, snapping, call-backs, and scroll-driven application behaviour.
Is CSS Scroll-Driven Animation better for performance?
Not universally. Native scroll-driven CSS can remove the need for JavaScript scroll tracking in suitable interactions, but actual performance still depends on animated properties, layout and paint work, DOM volume, measurement, and the rest of the page. Profile the production implementation instead of assigning performance to the tool name.
Can CSS Scroll-Driven Animations pin sections?
Pinning is primarily a layout problem rather than a feature of CSS Scroll-Driven Animations. Native position: sticky can cover many sticky storytelling layouts. ScrollTrigger provides explicit pinning integrated with its trigger and timeline model.
Are CSS Scroll-Driven Animations supported everywhere?
No. As of September 2026, MDN still marks important pieces including animation-timeline and animation-range as Limited availability. Check compatibility when shipping and preserve a usable fallback where the interaction matters.
Should I use CSS or ScrollTrigger in React and Next.js?
Use the same interaction test. Presentation-level progress effects are strong candidates for CSS. ScrollTrigger makes sense when a component needs richer runtime choreography, provided client boundaries, scoping, and cleanup are handled correctly. GSAP's useGSAP() hook is designed to handle React-specific context and cleanup concerns.