Frontend Lab
← 回到所有效果
G03S103gsap

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

💬 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

完整程式碼

RevealOnScrub.tsx
'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 很差(小螢幕看不出區間)

我踩過的坑

  1. once: true 不是 scrub:兩者邏輯不同。once 一觸即播完, scrub 跟著滾動進度。

  2. start/end 寫錯動畫太快結束:'top 90%' → 'top 50%' 表示「元素 頂端進入視口 90% 到 50% 區間」之間做完動畫。

  3. scrub: true 抖:用 0.3~0.6 數字,多一點緩衝。

相關效果

搜尋

按 ⌘K 隨時開啟