Css Scroll Driven Animations
CSS scroll-driven animations using animation-timeline: scroll() and view() with animation-range — zero-JS reading-progress bar (scaleX on compositor) and viewport-entry reveal, with @supports fallback for Firefox.
$ prime install @community/template-css-scroll-driven-animations Projection
Always in _index.xml · the agent never has to ask for this.
CssScrollDrivenAnimations [template] v1.0.0
CSS scroll-driven animations using animation-timeline: scroll() and view() with animation-range — zero-JS reading-progress bar (scaleX on compositor) and viewport-entry reveal, with @supports fallback for Firefox.
Loaded when retrieval picks the atom as adjacent / supporting.
CssScrollDrivenAnimations [template] v1.0.0
CSS scroll-driven animations using animation-timeline: scroll() and view() with animation-range — zero-JS reading-progress bar (scaleX on compositor) and viewport-entry reveal, with @supports fallback for Firefox.
Language
css
Body
<style>
/* ══ Pattern 1: Reading-progress bar ══════════════════════════════════
scaleX — compositor-only, no layout cost.
aria-hidden="true" on the element — it is decorative. */
.reading-progress {
position: fixed;
top: 0; left: 0;
width: 100%; height: 3px;
background: oklch(0.55 0.22 256);
transform-origin: left center;
z-index: 1000;
animation: progress-grow linear both;
animation-timeline: scroll(root);
}
@keyframes progress-grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* ══ Pattern 2: Element reveal on viewport entry ═══════════════════
animation-range: entry 0% entry 50% — animation completes when
50% of the element has entered the viewport. */
.reveal-card {
animation: reveal-up linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
@keyframes reveal-up {
from { opacity: 0; transform: translateY(40px); }
to { opacity: 1; transform: translateY(0); }
}
/* ══ Pattern 3: Section progress indicator ══════════════════════════
Only active while section is fully contained in viewport. */
.section-progress {
animation: grow-progress linear;
animation-timeline: view();
animation-range: contain 0% contain 100%;
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* ══ Reduced motion ══════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.reading-progress { display: none; }
.reveal-card { opacity: 1 !important; transform: none !important; animation: none !important; }
.section-progress { animation: none; }
}
/* ══ Progressive enhancement: hide gracefully in Firefox ═════════════ */
@supports not (animation-timeline: scroll()) {
.reading-progress { display: none; }
.reveal-card { opacity: 1; transform: none; animation: none; }
}
</style>
<!-- Usage:
<div class="reading-progress" aria-hidden="true"></div>
<article class="reveal-card">Card 1</article>
<article class="reveal-card">Card 2</article>
Decision matrix:
Simple reveal / progress bar → CSS scroll-driven ✓
Firefox coverage required → GSAP ScrollTrigger
Pinning / scrub timeline → GSAP ScrollTrigger
Zero JS required → CSS scroll-driven ✓
-->
Usage Notes
- Chrome 115+, Edge 115+, Safari 26+ — ~80% global coverage as of 2026.
- Firefox: flag only — use @supports not (animation-timeline) to gracefully degrade.
- Always animate transform/opacity — never width/height (triggers layout).
- animation-range named keywords: entry, exit, contain, cover. 'entry 0% entry 50%' is the reveal sweet-spot.
- GSAP ScrollTrigger is the correct fallback when Firefox coverage is required.
Accessibility
- All scroll-driven entrance animations must be disabled under prefers-reduced-motion.
- Progress bar is decorative — add aria-hidden='true'.
- Content must be visible without the animation (fill-mode: both + reduced-motion reset).
Loaded when retrieval picks the atom as a focal / direct hit.
CssScrollDrivenAnimations [template] v1.0.0
CSS scroll-driven animations using animation-timeline: scroll() and view() with animation-range — zero-JS reading-progress bar (scaleX on compositor) and viewport-entry reveal, with @supports fallback for Firefox.
Language
css
Body
<style>
/* ══ Pattern 1: Reading-progress bar ══════════════════════════════════
scaleX — compositor-only, no layout cost.
aria-hidden="true" on the element — it is decorative. */
.reading-progress {
position: fixed;
top: 0; left: 0;
width: 100%; height: 3px;
background: oklch(0.55 0.22 256);
transform-origin: left center;
z-index: 1000;
animation: progress-grow linear both;
animation-timeline: scroll(root);
}
@keyframes progress-grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* ══ Pattern 2: Element reveal on viewport entry ═══════════════════
animation-range: entry 0% entry 50% — animation completes when
50% of the element has entered the viewport. */
.reveal-card {
animation: reveal-up linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
@keyframes reveal-up {
from { opacity: 0; transform: translateY(40px); }
to { opacity: 1; transform: translateY(0); }
}
/* ══ Pattern 3: Section progress indicator ══════════════════════════
Only active while section is fully contained in viewport. */
.section-progress {
animation: grow-progress linear;
animation-timeline: view();
animation-range: contain 0% contain 100%;
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* ══ Reduced motion ══════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.reading-progress { display: none; }
.reveal-card { opacity: 1 !important; transform: none !important; animation: none !important; }
.section-progress { animation: none; }
}
/* ══ Progressive enhancement: hide gracefully in Firefox ═════════════ */
@supports not (animation-timeline: scroll()) {
.reading-progress { display: none; }
.reveal-card { opacity: 1; transform: none; animation: none; }
}
</style>
<!-- Usage:
<div class="reading-progress" aria-hidden="true"></div>
<article class="reveal-card">Card 1</article>
<article class="reveal-card">Card 2</article>
Decision matrix:
Simple reveal / progress bar → CSS scroll-driven ✓
Firefox coverage required → GSAP ScrollTrigger
Pinning / scrub timeline → GSAP ScrollTrigger
Zero JS required → CSS scroll-driven ✓
-->
Usage Notes
- Chrome 115+, Edge 115+, Safari 26+ — ~80% global coverage as of 2026.
- Firefox: flag only — use @supports not (animation-timeline) to gracefully degrade.
- Always animate transform/opacity — never width/height (triggers layout).
- animation-range named keywords: entry, exit, contain, cover. 'entry 0% entry 50%' is the reveal sweet-spot.
- GSAP ScrollTrigger is the correct fallback when Firefox coverage is required.
Accessibility
- All scroll-driven entrance animations must be disabled under prefers-reduced-motion.
- Progress bar is decorative — add aria-hidden='true'.
- Content must be visible without the animation (fill-mode: both + reduced-motion reset).
Source
prime-system/examples/frontend-design/primes/compiled/@community/template-css-scroll-driven-animations/atom.yaml