Communitygithub.com

KILN-skills/scroll-animation

使用 GSAP、ScrollTrigger、SplitText 與 Lenis 平滑滾動建構滾動驅動動畫——揭示效果、固定區段、水平滾動、視差、刷洗時間軸、文字效果——支援 Vanilla JS、React、Next.js、Vue/Nuxt 與 Astro,附正確設定、清理與響應式降級。每當使用者提及 GSAP、ScrollTrigger、Lenis、平滑滾動、視差、固定、刷洗、「動畫隨滾動」、水平滾動或滾動敘事時使用。

scroll-animation 是什麼?

此技能專為需要在網頁專案中實作進階滾動驅動動畫的開發者設計,涵蓋 GSAP、ScrollTrigger、SplitText 與 Lenis 平滑滾動的完整整合流程。它提供標準化的設定模組、跨框架(React、Vue、Astro、Vanilla JS)的整合最佳實務,並深入說明 ScrollTrigger 的關鍵規則以避免常見錯誤,例如避免在巢狀時間軸上設定 scrollTrigger、使用 `ease: 'none'` 搭配 `scrub`、以及正確處理固定區塊與響應式斷點。該技能強烈建議使用 `gsap.matchMedia()` 來處理響應式設計與減少動畫偏好,並在每個場景中包裹以確保健壯性。此外,它也包含效能最佳化建議(如動畫 transform 與 opacity 而非 layout 屬性)以及驗證測試清單(快速滾動、視窗縮放、SPA 導航等),幫助開發者產出無錯誤且高效能的滾動敘事體驗。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/KILN-skills/kiln/tree/HEAD/skills/scroll-animation

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

滾輪動畫(GSAP + ScrollTrigger + Lenis)

若已安裝 GreenSock 官方技能(gsap-core、gsap-scrolltrigger、gsap-react、gsap-plugins),請使用它們獲取 API 細節;此技能涵蓋專案設定、整合以及會破壞實際網站的常見錯誤。

1. 安裝

npm i gsap lenis
npm i @gsap/react   # 僅限 React / Next.js

所有 GSAP 外掛(ScrollTrigger、SplitText、Flip、ScrollSmoother、MorphSVG、DrawSVG…)都包含在公開發行的 gsap 套件中,且可免費商用。從 gsap/<PluginName> 導入並呼叫一次 gsap.registerPlugin(...)。

2. 一個設定模組

建立 lib/motion/setup.(js|ts)(或 animations/),在客戶端導入一次:

import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
import Lenis from "lenis";
import "lenis/dist/lenis.css";

gsap.registerPlugin(ScrollTrigger, SplitText);

export function initSmoothScroll() {
  if (matchMedia("(prefers-reduced-motion: reduce)").matches) return null;
  const lenis = new Lenis();
  lenis.on("scroll", ScrollTrigger.update);
  const tick = (time) => lenis.raf(time * 1000); // GSAP 時間以秒為單位,Lenis 需要毫秒
  gsap.ticker.add(tick);
  gsap.ticker.lagSmoothing(0);
  return () => { gsap.ticker.remove(tick); lenis.destroy(); };
}

請僅使用 Lenis 或 GSAP ScrollSmoother,不要同時使用兩者。

3. 框架整合

React / Next.js(App Router) — 使用 GSAP 的檔案需要 "use client"。務必使用 useGSAP(自動清理,嚴格模式下不會雙重執行):

"use client";
import { useRef } from "react";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(useGSAP, ScrollTrigger);

export function Features() {
  const root = useRef<HTMLElement>(null);
  useGSAP(() => {
    const mm = gsap.matchMedia();
    mm.add("(prefers-reduced-motion: no-preference)", () => {
      gsap.from(".feature", {
        autoAlpha: 0, y: 32, stagger: 0.08, ease: "power3.out",
        scrollTrigger: { trigger: root.current, start: "top 75%" },
      });
    });
  }, { scope: root }); // 選擇器限於此元件範圍
  return <section ref={root}>…</section>;
}
  • 建立動畫的事件處理器:使用 useGSAP 的 contextSafe 包裹。
  • 平滑滾動提供者:在根佈局的客戶端元件中,於 effect 內呼叫 initSmoothScroll()(或使用 lenis/react 的 ReactLenis,並設定 autoRaf: false 與 GSAP 的 ticker)。
  • Next.js 中的路由變更:滾動至頂端(lenis.scrollTo(0, { immediate: true })),並在新頁面掛載後呼叫 ScrollTrigger.refresh()。

Vue / Nuxt — 在 onMounted 內,使用 gsap.context(() => {…}, rootEl) 建立,並在 onUnmounted 中呼叫 ctx.revert()。Nuxt:使用僅限客戶端的外掛(plugins/gsap.client.ts)。

Astro / 靜態多頁面 — 在佈局中使用 <script>;若使用 View Transitions,在 astro:page-load 時重新初始化,並在 astro:before-swap 時銷毀觸發器。

Vanilla — 一個在 DOM 就緒後執行的 main.js;按區段使用 gsap.context() 分組。

4. 可避免 90% 錯誤的 ScrollTrigger 規則

  • 將 scrollTrigger 設定在時間軸或頂層 tween 上——絕不要設定在時間軸內部的巢狀 tween 上。
  • 使用 scrub 時搭配 ease: "none"。
  • 建立順序很重要:按頁面順序從上到下建立觸發器(或設定 refreshPriority),特別是在使用固定功能時。
  • 固定一個包裝器,而不是你正在動畫化的元素。不要在設有 transform 的父元素內部進行固定。除非有意為之,否則避免使用 pinSpacing: false。
  • 對於任何依賴視口大小的屬性,使用函數值(x: () => …)搭配 invalidateOnRefresh: true。
  • 在圖片、字型或動態內容改變佈局後,呼叫 ScrollTrigger.refresh()(window.addEventListener("load", …)、document.fonts.ready)。
  • 使用 markers: true 除錯——發布前記得移除。
  • 初始隱藏狀態:使用 gsap.from/fromTo 或由 JS 設定的 autoAlpha,以確保在沒有 JS 的情況下內容是可見的。
  • 對於不應重播的揭示效果(大多數情況),使用 once: true。

5. 響應式與減少動畫

將每個場景包裹在 gsap.matchMedia() 中:

const mm = gsap.matchMedia();
mm.add({
  isDesktop: "(min-width: 1024px)",
  isMobile: "(max-width: 1023px)",
  motionOK: "(prefers-reduced-motion: no-preference)",
}, ({ conditions: c }) => {
  if (!c.motionOK) return;            // 靜態佈局,無動畫
  if (c.isDesktop) { /* 固定 / 水平場景 */ }
  if (c.isMobile)  { /* 僅簡單淡入 */ }
});

matchMedia 在條件變化時會自動復原——無需手動清理。

6. 效能

  • 對 x/y/scale/rotation/autoAlpha(transform + opacity)進行動畫。避免對 width/height/top/left 以及大面積的 filter: blur() 進行動畫。
  • 每個區段偏好使用一個時間軸,而不是數十個單獨的觸發器;對於大量相同的揭示效果,使用 ScrollTrigger.batch。
  • 對於跟隨游標的效果,使用 gsap.quickTo。
  • 刷洗場景內的大圖片:使用合適的 sizes 屬性,並避免每一幀都縮放大型點陣圖。

7. 驗證

快速上下滾動整頁;縮放視窗;在頁面中間重新載入;導航離開再返回(SPA)——不應有跳動、不應有重複的固定元素、不應有主控台錯誤。在開啟減少動畫、375px 寬度以及啟用 CPU 節流的情況下進行測試。

常見效果配方:../motion-direction/references/patterns.md。

相關技能