Frontend Lab
← 回到所有效果
F12S003framer-motion

whileInView Trigger

視口觸發

難度 ★★★★標籤 滾動 · viewport · whileInView3 min read

效果簡述

不是動畫本身,是「動畫的觸發方式」。framer-motion 的 whileInView 是 60% 的時候你應該用的觸發器——不是 useScroll、不是 IntersectionObserver 手寫。

進入視口才觸發

once: true · amount: 0.5

預設|amount 0.4, once: true

Claude Code Prompt

💬 Claude Code Prompt
參考:S003 whileInView trigger
技術:Framer Motion 的 whileInView + viewport 選項

具體行為:
- whileInView 取代 animate,當元素進入視口才執行
- viewport: { once: true }(重要!)→ 只觸發一次
- viewport: { amount: 0.4 }→ 元素 40% 進入視口才觸發
- 配合 initial 設定起始狀態

限制:
- once: true 是預設應該加的,少數情境才會想反覆觸發
- amount 0.3 - 0.5 最自然;太低會還沒看到就動完,太高會等很久

完整程式碼

WhileInViewTrigger.tsx
'use client'

import { motion } from 'framer-motion'

export function WhileInViewTrigger() {
return (
  <motion.div
    initial={{ opacity: 0, y: 20 }}
    whileInView={{ opacity: 1, y: 0 }}
    viewport={{ once: true, amount: 0.5 }}
    transition={{ duration: 0.5, ease: [0.4, 0, 0.2, 1] }}
  >
    進入視口才觸發
  </motion.div>
)
}

何時用

  • ✅ 任何「滾動到才出現」的進場動畫
  • ✅ 章節分隔、卡片列表、figure 圖片
  • ✅ 取代手寫 IntersectionObserver

何時別用

  • ❌ 頁面載入立刻要動的元素(用 animate 不要用 whileInView)
  • ❌ 已經在 viewport 內的元素也想要進場(會立刻觸發,看不到動畫) → 解法:先 setTimeout 一下再 mount,或用 useEffect 切換 state

我踩過的坑

  1. viewport once 沒加 = 災難:使用者滾上滾下會一直觸發動畫, 像鬼打牆。一律 viewport={{ once: true }},除非你「真的」需要 重複觸發(極少數)。

  2. 手機 amount 要降一點:手機畫面高度小,amount: 0.5 可能整個元素 都進來才觸發,感覺很慢。手機建議 0.3。可以判斷 window.innerHeight 切換。

  3. 動畫到一半離開視口會凍在那裡:因為 once: true 後 framer 不會「回退」。解法:要嘛接受這個行為,要嘛 once: false 但這樣 就會反覆觸發——所以最好的辦法是讓 duration 短一點(< 0.7s)。

相關效果

搜尋

按 ⌘K 隨時開啟