Skip to main content

scroll-animations

Build scroll-triggered reveals and scroll-driven animation with the restraint and craft bar of the "Animations on the Web" course (animations.dev) — and know when a scroll animation shouldn't exist at all. Use when adding fade-in-on-scroll reveals to a landing page, building progress-linked (scrubbed) animation, parallax, sticky scrollytelling sections, or fixing scroll animation that re-triggers, stutters, hides content, or hijacks scrolling. Triggers on — scroll animation, scroll-driven, fade in on scroll, reveal on scroll, animate on scroll, AOS, scroll trigger, ScrollTrigger, IntersectionObserver, useInView, useScroll, scrollYProgress, animation-timeline, scroll(), view(), scroll-timeline, parallax, sticky section, scrollytelling, scroll progress, reading progress bar, scroll hijacking, smooth scroll, scroll-behavior, Lenis, locomotive scroll, "sections fade in", "animate as you scroll", "re-animates when I scroll back up".

Quellinformationen

Repository
Subhan-code/oxygen-ui-solana
Letzte Quellaktivität
30. August 2026 um 18:11
Erkannte Sprache von SKILL.md
Englisch
Sterne
18
Forks
4

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
scroll-animations
description
Build scroll-triggered reveals and scroll-driven animation with the restraint and craft bar of the "Animations on the Web" course (animations.dev) — and know when a scroll animation shouldn't exist at all. Use when adding fade-in-on-scroll reveals to a landing page, building progress-linked (scrubbed) animation, parallax, sticky scrollytelling sections, or fixing scroll animation that re-triggers, stutters, hides content, or hijacks scrolling. Triggers on — scroll animation, scroll-driven, fade in on scroll, reveal on scroll, animate on scroll, AOS, scroll trigger, ScrollTrigger, IntersectionObserver, useInView, useScroll, scrollYProgress, animation-timeline, scroll(), view(), scroll-timeline, parallax, sticky section, scrollytelling, scroll progress, reading progress bar, scroll hijacking, smooth scroll, scroll-behavior, Lenis, locomotive scroll, "sections fade in", "animate as you scroll", "re-animates when I scroll back up".
metadata
{"short-description":"Scroll reveals and scroll-driven motion with restraint (animations.dev)"}
# Scroll Animations Scroll animation held to the *Animations on the Web* course bar ([animations.dev](https://animations.dev/)). Scroll is the most abused trigger in web motion, so this skill is half restraint, half implementation — in that order. The scrollbar belongs to the user: motion may respond to scrolling, but must never take it over or make content wait. ## Gate: should this scroll animation exist? Walk this before writing any code: ``` Is this inside a product (dashboard, app, tool)? ├── Yes → No scroll animation. Users scroll product UI dozens of times a │ session; content appearing late reads as lag, not delight. └── No — it's a marketing surface (landing page, blog, docs) ├── Is the element in the initial viewport (above the fold)? │ └── Yes → Don't scroll-reveal it. Use a one-time intro animation │ or nothing. The hero must never wait for a scroll event. ├── Are you about to reveal EVERY section? │ └── Yes → Cut it to 2–4 moments. If everything animates, nothing │ stands out — each reveal devalues the next. └── Does it explain, pace, or emphasize something specific? ├── Yes → Build it (rules below). └── No ("it looks cool") → The best animation is no animation. ``` Marketing pages are the packaging of the product — they've earned slower, more expressive motion because they're seen rarely. That freedom is the *reason* to be selective, not a license to animate everything. ## Two kinds — never confuse them Every scroll animation is one of these; the wrong choice is unfixable by tuning: - **Triggered reveal** — crossing a threshold *starts* a normal animation that then runs on its own clock (easing + duration). For "fade in as it enters the viewport." - **Scrubbed** — scroll position *is* the clock; progress maps directly to animation progress and reverses when the user scrolls back. For progress bars, parallax, sticky sequences. A scrubbed animation has **no duration and no easing** — the user's hand is both. Adding a duration to scrubbed motion makes it lag behind the scrollbar, the same disconnected feeling as a spring during a drag. ## Triggered reveals - **Reveal once. Never re-animate on scroll-up.** Intro animations run one time — replaying on every pass turns delight into a tic and makes content flicker during normal reading. Unobserve after firing (or `once: true` in Motion's `useInView`). - **The recipe:** `opacity: 0` + `translateY(10–16px)` → settle, with a strong `ease-out` (entering elements always ease out — the fast start reads as responsive). 400–600ms is right for marketing; product-speed 200ms reveals look nervous on a landing page. - **Trigger early.** Start the animation when the element is ~10–20% into the viewport (`rootMargin: "0px 0px -10% 0px"`), so it plays *as* the user arrives, not after they've stopped and stared at a blank slot. - **Stagger like a wave, not a metronome.** Sibling reveals offset by ~80–120ms, with delay and distance varied by importance — the heading leads, supporting text follows, the least important item can just fade with no movement. Uniform stagger kills hierarchy. - **Content survives without JS.** The un-animated state is *visible*; JS adds the hidden initial state right before animating. A page of `opacity: 0` sections behind a broken script is the worst failure mode a marketing page has. - **One entrance per container.** Don't reveal a section *and* stagger its children — pick one. Implementation: `IntersectionObserver` (or Motion's `useInView`) toggling a class. Never a scroll listener — it fires per frame on the main thread for work a threshold check does once. ## Scrubbed animation Preference order, and why: 1. **CSS scroll-driven animations** — `animation-timeline: view()` (element's own viewport progress) or `scroll()` (container progress). They run off the main thread, stay hooked to the scrollbar even while the page is busy loading images, and cost no JS. Progressive-enhance: wrap in `@supports (animation-timeline: view())` with the no-animation state as fallback. 2. **Motion's `useScroll` + `useTransform`** — when progress must feed React logic or compose with springs/gestures. This runs on the main thread via rAF: fine normally, drops frames under load. 3. **A raw scroll listener writing React state** — never. A re-render per scrolled pixel. ```css @supports (animation-timeline: view()) { .figure { animation: reveal linear both; animation-timeline: view(); animation-range: entry 0% cover 40%; } } ``` `linear` is correct here and only here — the scrubbed timeline's pacing comes from the user's hand, and any curve would distort the 1:1 mapping. ## Parallax Parallax is depth seasoning, and heavy-handed parallax is the fastest way to make a page feel like 2014: - **Keep the differential ≤ ~15%** of scroll distance between layers. Enough to read as depth; more reads as content swimming. - **Transform only**, scrubbed (no duration), decorative elements only — never body text, never anything the user needs to read while it moves. - **Disable on `prefers-reduced-motion`** entirely — parallax is the canonical vestibular trigger, and it's decorative, so the reduced variant is *none*, not gentler. - Skip it on mobile: short viewports and momentum scrolling turn subtle parallax into jitter. ## Sticky / scrollytelling sections A section that pins while scroll drives a sequence is an **explanation** device — it earns its scroll length only if each increment reveals a step of a story. Rules: progress maps monotonically to the sequence (scrolling back rewinds it); keep the pinned length ≤ ~2–3 viewport heights, because trapped-feeling sticky sections are where users close tabs; and the section must be skippable by simply continuing to scroll — never block or slow the scrollbar to force the story. ## Never hijack scroll No scroll-jacking, no rewriting wheel deltas, no "one wheel tick = one full-screen slide." Smooth-scroll libraries that re-implement scrolling on the main thread trade native responsiveness for a float that many users read as lag. If you add `scroll-behavior: smooth` for anchor links, gate it: ```css @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } } ``` ## Performance The golden rule holds: **animate only `transform` and `opacity`** — a scrolling page is the worst place for layout-triggering properties, since Layout/Paint work stacks on top of the scroll itself. Add `will-change: transform` on scrubbed elements only (they animate for the whole scroll, so the dedicated layer pays for itself — on one-shot reveals it's wasted memory). Keep any animated `blur()` ≤ 20px; blur gets laggy fast, especially in Safari. If reveals stutter, use the `animation-performance` skill. ## Reduced motion Gentler, not zero: reveals keep the opacity fade and drop the translate; scrubbed decorative motion (parallax, floating shapes) turns off entirely; smooth scrolling turns off. The `animation-accessibility` skill has the full two-variant workflow. ## Related skills Deciding *whether* a page moment deserves motion at all → `find-animation-opportunities`. Entrances not tied to scroll (hero intros) → `animate`. CSS-only implementation details → `css-animations`.
Auf GitHub ansehen