連續講了五天的鬼故事後,今天打開電腦,腦袋還是空空的,感覺去年的這些事還歷歷在目,簡直 PTSD...
在前幾篇文章中,提到有陣子我一直在忙前公司承接的案子。這一開始是由一位前同事開發,直到他要離職,才交接給我,而當時只剩下其中一個頁面需要我接手。我稍微了解一下專案內部之後,不得不稱讚這位前同事寫得好乾淨,首頁更是炫的不得了!是一台 3D 太空船模型,搭配背景的空間模型,藉由 GSAP 的 ScrollTrigger,讓使用者滾動頁面時,觸發播放兩個模型的 glb 檔中的動畫,看起來真的就像有一台太空船在瀏覽器中飛翔一樣!
今天就來簡單介紹 GSAP (GreenSock Animation Platform)~它是一個非常強大的 JavaScript 動畫函式庫,很適合用來製作複雜、精確且流暢的網頁動畫,裏面供許多的 API 可以讓程式碼既乾淨又能達到需求。
其中,ScrollTrigger 是 GSAP 最受歡迎的插件之一,可以讓你在「畫面捲動到某個位置」時觸發或控制 GSAP 動畫,也就是,它主要是依靠「位置」來觸發動畫。來簡單介紹一下如何使用吧:
招喚滾動的魔法卷軸第一步:安裝
npm install gsap @gsap/react
招喚滾動的魔法卷軸第二步:匯入與註冊
GSAP 的外掛必須手動註冊才能使用
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";
gsap.registerPlugin(ScrollTrigger);
招喚滾動的魔法卷軸第三步:建立滾動
範例:當使用者往下滾動到 .box 時,它會從左側滑入並旋轉
"use client";
import { useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";
gsap.registerPlugin(ScrollTrigger);
export default function App() {
const boxRef = useRef(null);
// useGSAP 會在組件掛載後執行動畫
useGSAP(() => {
gsap.to(boxRef.current, {
x: 300, // 往右移動 300px
rotation: 360, // 順時針旋轉 360 度
duration: 2, // 動畫持續 2 秒
scrollTrigger: {
trigger: boxRef.current, // 觸發元素
start: "top 80%", // 元素頂端到視窗 80% 時觸發
end: "bottom 20%", // 元素底端到達視窗 20% 時結束
scrub: true, // 動畫隨滾動進度移動
markers: true, // 顯示輔助線(開發時可開啟true)
},
});
}, []);
return (
<div className="h-[200vh] flex items-center justify-center">
<div ref={boxRef} className="w-20 h-20 bg-blue-500"></div>
</div>
);
}
這個只是單一元素的動畫,如果有多個元素要依序動畫,可以搭配 Timeline 來做:
"use client";
import { useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";
gsap.registerPlugin(ScrollTrigger);
export default function App() {
const sectionRef = useRef<HTMLDivElement>(null);
useGSAP(() => {
const tl = gsap.timeline({
scrollTrigger: {
trigger: sectionRef.current,
start: "top 80%",
end: "bottom 20%",
scrub: 1,
markers: true,
},
});
// 定義時間軸動畫
tl.to(".title", { opacity: 1, y: -30, duration: 1 })
.to(".image", { scale: 1.2, duration: 1 })
.to(".text", { x: 100, opacity: 1, duration: 1 });
}, []);
return (
<div className="h-[200vh] bg-gray-100">
{/* 用來讓畫面可滾動的空白區塊 */}
<div className="h-[100vh] flex items-center justify-center text-gray-400">
<p>往下滾動開始動畫</p>
</div>
{/* 主要動畫區域 */}
<section ref={sectionRef} className="section flex flex-col items-center justify-center h-[100vh] bg-white rounded-2xl shadow-lg mx-auto w-3/4 p-10">
<h2 className="title opacity-0 text-4xl font-bold mb-6">
滾動觸發動畫
</h2>
<img
src="https://placekitten.com/300/200"
alt="kitten"
className="image w-60 h-40 object-cover rounded-lg mb-6"
/>
<p className="text opacity-0 text-lg text-gray-700 max-w-md text-center">
當你往下滾動時,文字、圖片與標題會依序出現。
<br />
這是 ScrollTrigger + Timeline 的範例。
</p>
</section>
{/* 增加底部空間讓滾動自然結束 */}
<div className="h-[100vh]"></div>
</div>
);
}