網頁前端特效動畫 GSAP 教學[入門02] [流程]

GSAP Timeline:較長的動畫,如何在gsap上管理,與 Tween差異又是什麼。

Jay Wu
7 min readJul 26, 2020

覺得GSAP一次性的動畫與 jQuery 去改變 style雷同 ?
覺得GSAP與新增 Class調整樣式,沒什麼區別嗎 ?
介紹GSAP流水線(Timeline)的動畫,比擬 CSS animation 多重 Keyframes。

GSAP 的(Timeline)動畫線如樹枝蔓延
子父層關係可以不斷堆疊

常用的Tween屬性設定

所有 Tween 屬性可以參考官方文件

// Tween
gsap.to('#target', {
x: 100,
ease: 'power2.out', // 速度曲線
duration: 1, // 動畫時間 預設單位:秒
delay: 0, // 延遲 預設單位:秒
repeat: 2, // 重複播放動畫幾次,無限:-1
})

快速建立動畫的方法

使用 Timeline 新增 Tween

GSAP 的 Timeline 提供了三種建立動畫 (Tween) 的方法
建立後的動畫 Tween,為 Timeline 子層 `Timeline.getChildren()`

  1. to
  2. from
  3. fromTo

跟gsap一樣

  • gsap.to
  • gsap.from
  • gsap.fromTo

但 Timeline 建立的function都會回傳自己本身(Ref)

  1. 可像 jQuery 一樣一路往下寫
  2. 好閱讀、好修改、好理解的
  3. 預設會銜接上一個動畫
gsap.timeline() // return Timeline
.to('#target',{x: 100}) // return Timeline
.to('#target',{y: 100}) // return Timeline
.to('#target',{x: 200}) // return Timeline
.to('#target',{y: 200})
// (0, 0) -> (100, 0) -> (100, 100) -> (200, 100) -> (200, 200)

也可以將已存在的動畫(Tween)收納(add)

var Container = gsap.timeline()          // 時間線
var First = gsap.to('#target', {x: 100}) // 動畫1
var Second = gsap.to('#target',{y: 100}) // 動畫2
// Timeline.add(Tween)
Container.add(First) // 將 Tween 加入 Timeline 內
Container.add(Second)
Container.getChildren() // 查詢子物件 return [Tween, Tween]
Container.play(0) // 時間線從 0秒開始撥放

不常使用的 keyframes 屬性

Tween 內 keyframes 將單個動畫分割

在 Tween Properties 中提供 keyframes 這個屬性
與CSS keyframes 雷同,可以設定多個斷點
又與 Timeline 新增Tween 相似

// 以陣列(Array)方式
gsap.to('#target', {
keyframes:[
{x: 100}, // 0%
{y: 100}, // 33.333%
{x: 200}, // 66.666%
{y: 200} // 100%
]
})

那 Tween 的 keyframe 跟 Timeline 差在哪?

若符合以下條件:

  1. 總時間相同 (Duration)
  2. 路徑比例設定相同 (Keyframes & Tween)
  3. 速度曲線為 “linear” (Ease: ‘none’)

Tween 的 keyframes 與 Timeline 沒有區別

// 黑:Tween 的 keyframes,
// 紅:Timeline
看code:

如何串接成你的 ”電影” ?

Timeline 也可以收納 Timeline (套娃)

當你已經寫完一整串可()觀()的 Timeline 動畫
有做過動畫的人應該熟悉,跟AE的Comp一樣
想與其他人的動畫串接時,就是再創建一個Comp做收納

而不管是被收入的 Timeline or Tween
都會依照加入原本的順序做遍歷播放

舉例1:
兩層的結構
Timeline 收納 TA_1 (Timeline)A_2 (Tween)
動畫順序為: TA_1(Timeline) → A_2(Tween)

sumTimeline = [ TA_1, A_2 ] // TA_1 -> A_2

承上題:
TA_1 (Timeline) 本來有收納 A_1_1 (Tween) A_1_2 (Tween)
動畫順序為:
A_1_1 (Tween) → A_1_2 (Tween) → A_2 (Tween)

flatTimeline = [ [ A_1-1, A_1-2 ], A_2 ]  // A_1-1 -> A_1-2 -> A_2

範例:

var animation_1 = gsap.to(...);
var animation_2 = gsap.timeline(...)
.to(...)
.to(...)
...
// 加總兩個動畫var animationSum = gsap.timeline()
.add(animation_1)
.add(animation_2)
// getChildren 會回傳目前timeline的子動畫
animationSum.getChildren() // =>[Tween, Timeline]
animationSum.play(0) // animation_1 -> animation_2

// 紅色:Timeline
// 黑色:Tween
// 全部: 紅+黑

看Code:

— — — — — — — — — — — — 以下水深提醒— — — — — — — — — —

使用 keyframes 與 Timeline 有什麼區別?

| 若在有速度變化(ease)的動畫中,會有整體速度曲線不同的差異 |

對速度變化有興趣的話,可以先詳閱 Ease 官方文件
或參閱我的
動畫速度曲線直線相關(ease)的章節

事實上,有 keyframes 的Tween 納入 Timeline
就是 Timeline產生多個 Tween

在上面的 Codepen 中,若使用 getChildren 你會發現
我們使用 keyframes 的 Tweens, 在被 Timeline 納入後
還是會被轉成對映數量的 Tween,跟一開始用 Tween 沒兩樣
那問題來了...

那如果知道要做大量動畫的話,一開始用 Timeline 去串接就好。

整體速度曲線不同的區別是?

Tween 的 keyframes 速度變化來自於 Tween 設定的 ease
Timeline 速度變化,來自於各個 Tween 設定的 ease
多個 Tween 的 ease 屬性總和 (linear 會沒有差異)

藍色: Timeline
紅色: Tween keyframes

看圖表:

ease

實體範例:

// 黑:單一速度曲線 (Tween),使用 keyframe,並設定 ease 值
// 紅:分段速度曲線 (Timeline),統一設定 defaults ease 值

看Code:

經過的路徑其實是相同的
開始與結束時間也是相同的
同樣也都對這兩個動畫增加了相同的ease(不為 ’none’ [linear] )

Tween 版本的 ease,會對整個動畫曲線做調整
Timeline 是各別的 Tween 做 ease 設定,自己內部做 ease 動畫

總結與進階

針對不同需求做使用,釐清原理比較重要
如果想要強制混合 Timeline 內的 ease 的話,可以參考 Timeline 的設定
官方有出付費版的Debug工具,有興趣可以參考

前端特效動畫 GSAP 教學 [入門01][大綱]
前端特效動畫 GSAP 教學[入門02] [流程]
前端特效動畫 GSAP 教學[入門03][播放]
前端特效動畫 GSAP 教學 [入門04][ease]
前端特效動畫 GSAP 教學[入門05][交錯]

--

--

Jay Wu

網頁前端工程師。切版、特效開發、平面互動,沒時間記錄技術文章。逐漸陷入科技藝術窮途的沒錢工程師。