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".

ソース情報

リポジトリ
Subhan-code/oxygen-ui-solana
ソースの最終更新活動
2026年8月30日 18:11
検出された SKILL.md の言語
英語
スター
18
フォーク
4

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
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`.
GitHubで見る