G03▸S103▸gsap
Reveal on Scrub
滾動進度驅動進場
難度 ★★★★★標籤 scrollTrigger · scrub · reveal3 min read
效果簡述
跟 whileInView 不一樣 —— 進場「不是一口氣播完」,而是「跟著滾動
進度逐格 reveal」。觀感更精緻、stop-and-go 的閱讀節奏也更好控制。
↓ 滾我 · from: y
區塊 1 — 被滾動帶出來
區塊 2 — 被滾動帶出來
區塊 3 — 被滾動帶出來
區塊 4 — 被滾動帶出來
區塊 5 — 被滾動帶出來
區塊 6 — 被滾動帶出來
區塊 7 — 被滾動帶出來
區塊 8 — 被滾動帶出來
Claude Code Prompt
參考:S103 reveal on scrub
技術:gsap + ScrollTrigger scrub(不是 once)
具體行為:
- gsap.utils.toArray('.reveal').forEach(el => gsap.from(el, { y: 40, opacity: 0, scrollTrigger: { trigger: el, start: 'top 90%', end: 'top 50%', scrub: 0.5 } }))
- start/end 控制「進場區間」
- scrub 0.3~0.6 比較自然
限制:
- 不要對所有區塊一律使用(跟 once-fade-in 混用較好)
- 區塊高度需要 > 200px 才看得出 scrub 過程
- 父層別 overflow-hidden完整程式碼
'use client'
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { useEffect, useRef } from 'react'
export function RevealOnScrub() {
const root = useRef<HTMLDivElement>(null)
useEffect(() => {
gsap.registerPlugin(ScrollTrigger)
const ctx = gsap.context(() => {
gsap.utils.toArray<HTMLElement>('.reveal').forEach((el) => {
gsap.from(el, {
opacity: 0,
y: 40,
scrollTrigger: {
trigger: el,
start: 'top 90%',
end: 'top 50%',
scrub: 0.5,
},
})
})
}, root)
return () => ctx.revert()
}, [])
return (
<div ref={root}>
{/* .reveal 區塊們 */}
</div>
)
}何時用
- ✅ 長文章 / 案例文
- ✅ scrollytelling 章節
- ✅ 配 sticky 元素一起用
何時別用
- ❌ Hero 區(進入時應該直接呈現)
- ❌ 表格列 / 列表(會逐項 scrub 很煩)
- ❌ 行動 mobile 很差(小螢幕看不出區間)
我踩過的坑
-
once: true不是 scrub:兩者邏輯不同。once 一觸即播完, scrub 跟著滾動進度。 -
start/end 寫錯動畫太快結束:'top 90%' → 'top 50%' 表示「元素 頂端進入視口 90% 到 50% 區間」之間做完動畫。
-
scrub: true 抖:用 0.3~0.6 數字,多一點緩衝。
相關效果
- G01 Pin Section + Scrub — 進階版
- F12 whileInView Trigger — Framer 一觸即發版