CSS Is Coming for Your Scroll Animations (Politely)
Categories
For years, animation on the web has lived in a delicate truce.
CSS handled the simple stuff – transitions, keyframes, hover states.
JavaScript handled the good stuff – scroll-based animation, timelines, orchestration, and nuance. That division is about to blur in a big way.
Enter CSS progress() – an upcoming feature that gives CSS something it’s never truly had before: awareness of progress. And once CSS understands progress, animation becomes a very different conversation.
The Core Problem CSS Has Always Had
CSS animations have always been time-based, not state-based.
You could say:
- “Animate this over 1s”
- “Ease it like this”
- “Loop it forever”
But you couldn’t say:
- “Animate this as the user scrolls”
- “Tie this value to how far something has progressed”
- “Map one motion directly to another”
JavaScript libraries (GSAP especially) stepped in to fill that gap – and did it brilliantly.
CSS progress() is the browser saying:
“We can do that now.”
What Is progress()?
At a high level, progress() exposes a normalized 0 → 1 value representing how far something has progressed through a defined range.
That range might be:
- Scroll position
- An animation timeline
- A view-based interaction
- A container’s visibility
Instead of calculating progress in JavaScript, CSS can now react to it directly.
Think of it as CSS finally getting a slider knob.
A Simple Mental Model
Imagine this:
opacity: progress(scroll) * 1;
transform: translateY(progress(scroll) * 100px);
That’s not final syntax – but conceptually, that’s what’s happening.
- At the start →
progress()= 0 - At the end →
progress()= 1 - Everything in between is smoothly interpolated
No scroll listeners
No requestAnimationFrame
No math in JS
No sync issues
Just… CSS.
Why This Is a Big Deal for Animation
1. CSS Becomes Reactive (Not Just Decorative)
This is the real shift.
CSS has traditionally reacted to state changes:
- hover
- focus
- active
- media queries
progress() makes CSS reactive to continuous input.
That’s enormous.
Scroll-driven fades, parallax, reveals, counters, transforms – all become native, declarative behaviors.
2. Animations Become Easier to Reason About
When animation logic lives in JS:
- You manage lifecycle
- You manage cleanup
- You manage timing and sync
- You manage resize edge cases
With progress():
- The browser owns the timing
- The browser owns the sync
- The browser owns invalidation
You describe what should happen, not how to compute it.
That’s a massive cognitive win.
3. Performance Is Likely to Be Better (Yes, Really)
Short answer: yes – in most cases, it will perform better.
Why?
Because:
- It runs closer to the rendering engine
- It avoids JS → layout → paint feedback loops
- It can be optimized at the compositor level
- It avoids main-thread JavaScript work during scroll
JavaScript animation libraries are incredibly optimized – GSAP especially – but they still have to run JavaScript.
Native CSS progress-based animation:
- Requires no JS execution per frame
- Can skip frames intelligently
- Can be hardware-accelerated more predictably
This matters most on:
- Low-power devices
- Long scrolling pages
- Heavy DOM environments
- Embedded or constrained contexts
So… Does This Kill GSAP?
No. Not even close. And this is important.
GSAP Still Wins At:
- Complex timelines
- Sequenced choreography
- Physics-based motion
- Cross-property orchestration
- Dynamic runtime logic
- Audio-synced animation
- Highly interactive games & experiences
What progress() does is eliminate the need for JS in a huge class of animations that should never have required it in the first place.
Think:
- Scroll fades
- Parallax layers
- Simple reveals
- Progress-based transforms
- Viewport-driven effects
That’s not replacing GSAP – that’s freeing it to be used where it actually shines.
Why “Less JavaScript” Is a Good Thing (Even If You Love JS)
This isn’t about ideology.
It’s about fit for purpose.
If the browser can do something natively:
- It’s usually more stable
- It’s usually more accessible
- It’s usually more performant
- It’s usually easier to maintain
Using JavaScript for animation when CSS can do it natively is like using a power tool to turn a screw.
Fun? Yes.
Necessary? No.
The Bigger Picture: CSS Is Growing Up
Between:
@scroll-timelineview-timelinecontainer querieshas()- and now
progress()
CSS is no longer just a styling language.
It’s becoming a behavioral language.
Not a replacement for JavaScript – but a partner that finally pulls its weight.