開始使用 CSS 中的捲動式動畫

1. 事前準備

捲動驅動動畫可讓您根據捲動容器的捲動位置,控制動畫的播放情形。也就是說,向上或向下捲動時,動畫會向前或向後掃動。此外,您也可以使用捲動驅動動畫,根據元素在捲動容器中的位置控制動畫。您可以藉此建立有趣的特效,例如視差背景圖片、捲動進度列,以及捲動到特定位置時才會顯示的圖片。

Chrome 115 新增支援一組 JavaScript 類別和 CSS 屬性,方便您輕鬆建立宣告式捲動驅動動畫。這些新 API 可與現有的 Web Animations 和 CSS Animations API 搭配使用。

本程式碼研究室會說明如何使用 CSS 建立捲動驅動動畫。完成本程式碼研究室後,您將熟悉這項令人期待的功能所導入的許多新 CSS 屬性,例如 scroll-timelineview-timelineanimation-timelineanimation-range

課程內容

  • 瞭解如何使用 CSS 中的捲動時間軸,建立視差背景效果。
  • 如何使用 CSS 中的捲動時間軸建立進度列。
  • 如何使用 CSS 中的 View Timeline 建立圖片顯示效果。
  • 如何在 CSS 中指定不同類型的 View 時間軸範圍。

軟硬體需求

請準備下列其中一組裝置:

  • 在 ChromeOS、macOS 或 Windows 上使用最新版 Chrome (115 以上版本),並將「Experimental Web Platform Features」旗標設為啟用。
  • 對 HTML 有基本瞭解
  • 對 CSS 有基本瞭解,尤其是 CSS 中的動畫

2. 做好準備

本專案所需的一切內容都放在 GitHub 存放區中。如要開始使用,請複製程式碼,然後在您慣用的開發環境中開啟。

  1. 開啟新的瀏覽器分頁,然後前往 https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab
  2. 複製存放區。
  3. 在想用的 IDE 中開啟程式碼。
  4. 執行 npm install 安裝依附元件。
  5. 執行 npm start 並前往 http://localhost:3000/
  6. 或者,如果沒有安裝 npm,請在 Chrome 中開啟 src/index.html 檔案。

3. 瞭解動畫時間軸

根據預設,附加至元素的動畫會在文件時間軸上執行。也就是說,網頁載入時,動畫會隨著時間推進。這是預設動畫時間軸,也是您目前唯一可存取的動畫時間軸。

使用捲動驅動動畫時,您會取得兩種新的時間軸:

  • 捲動進度時間軸
  • 查看進度時間軸

在 CSS 中,可以使用 animation-timeline 屬性將這些時間軸附加至動畫。請參閱下文,瞭解這些新時間表代表的意義,以及彼此間的差異。

捲動進度時間軸

捲動進度時間軸是動畫時間軸,會連結至捲動容器 (也稱為捲動埠或捲動器) 沿特定軸的捲動位置進度。這項函式會將捲動範圍中的位置轉換為時間軸的進度百分比。

開始捲動位置代表 0% 的進度,結束捲動位置則代表 100% 的進度。在下方的視覺化效果中,請注意,當您向下捲動捲軸時,進度會從 0% 增加到 100%。

查看進度時間軸

這類時間軸會連結至捲動容器中特定元素的相對進度。與捲動進度時間軸類似,系統會追蹤捲動器的捲動偏移。與捲動進度時間軸不同,進度取決於主體在捲動器中的相對位置。這與 IntersectionObserver 類似,可追蹤元素在捲軸中的顯示程度。如果元素在捲動器中不可見,則不會相交。如果可捲動容器內顯示該元素 (即使只有一小部分),即為相交。

當主體開始與捲軸相交時,系統就會開始計算「查看進度時間軸」,並在主體停止與捲軸相交時結束計算。在下圖中,請注意,當主體進入捲動容器時,進度會從 0% 開始向上計數,並在主體離開捲動容器時達到 100%。

根據預設,連結至「檢視進度時間軸」的動畫會附加至整個範圍。從主體進入捲動檢視區塊開始,到主體離開捲動檢視區塊為止。

您也可以指定要附加的範圍,將其連結至「查看進度時間軸」的特定部分。舉例來說,只有在主體進入捲動器時,在下方的視覺化圖片中,當主體進入捲動容器時,進度會從 0% 開始向上計數,但從完全交集的那一刻起,進度就會達到 100%。

您可以指定下列觀看時間軸範圍:covercontainentryexitentry-crossingexit-crossing。這些範圍會在程式碼研究室的後續部分說明,但如果您想搶先瞭解,請使用 https://goo.gle/view-timeline-range-tool 的工具,查看每個範圍代表的意義。

4. 建立視差背景效果

要新增至網頁的第一個效果,是主要背景圖片的視差背景效果。向下捲動頁面時,背景圖片應該會移動,但速度不同。為此,您需要使用捲動進度時間軸。

如要實作這項功能,請完成下列兩個步驟:

  1. 建立動畫,移動背景圖片的位置。
  2. 將動畫連結至文件的捲動進度。

建立動畫

  1. 如要建立動畫,請使用一般主要畫面格。在其中,將背景位置從垂直 0% 移至 100%:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. 現在,請將這些主要畫面格附加至主體元素:

src/styles.css

body {
  animation: 1s linear move-background;
}

使用這段程式碼,即可將 move-background 動畫新增至 body 元素。其 animation-duration 屬性設為一秒,並使用 linear 緩和效果。

如要建立捲動進度時間軸,最簡單的方法是使用 scroll() 函式。這會建立匿名捲動進度時間軸,您可以將其設為 animation-timeline 屬性的值。

scroll() 函式會接受 <scroller><axis> 引數。

<scroller> 引數可接受下列值:

  • nearest。使用最接近的祖先捲動容器 (預設)。
  • root:使用文件檢視區塊做為捲動容器。
  • self:使用元素本身做為捲動容器。

<axis> 引數可接受下列值:

  • block:沿著捲動容器的區塊軸測量進度 (預設)。
  • inline。使用捲動容器內嵌軸的進度測量值。
  • y:使用捲動容器 Y 軸的進度測量值。
  • x:使用捲動容器 X 軸的進度測量值。

如要將動畫連結至區塊軸上的根捲軸,要傳遞至 scroll() 的值為 rootblock。因此值為 scroll(root block)

  • scroll(root block) 設為主體上的 animation-timeline 屬性值。
  • 此外,以秒為單位表示 animation-duration 並無意義,因此請將時間長度設為 auto。如未指定 animation-duration,系統會預設為 auto

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

由於根捲軸也是 body 元素最接近的父項捲軸,因此您也可以使用 nearest 值:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

由於 nearestblock 是預設值,您甚至可以選擇省略這些值。在這種情況下,程式碼可以簡化為:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

驗證變更

如果一切順利,您現在應該會看到以下內容:

如果沒有,請查看程式碼的 solution-step-1 分支。

5. 為圖片庫建立進度列

頁面上的水平輪轉介面需要進度列,才能指出目前查看的相片。

輪轉介面的標記如下所示:

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

進度列的影格已就位,如下所示:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

這個動畫必須附加至 。元素,並搭配捲動進度時間軸。gallery__progress如上一個步驟所示,您可以使用 scroll() 函式建立匿名捲動進度時間軸,即可達成此目的:

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

雖然這段程式碼看似可行,但由於使用 nearest 的自動捲動容器查詢方式,因此無法運作。在尋找最近的捲動器時,元素只會考慮可能影響其位置的元素。由於 .gallery__progress 是絕對定位,因此決定其位置的第一個父項元素是 .gallery 元素,因為該元素已套用 position: relative。也就是說,系統在自動查閱時,完全不會考慮 .gallery__scrollcontainer 元素 (需要做為目標的捲動器)。

如要解決這個問題,請在 .gallery__scrollcontainer 元素上建立具名的捲動進度時間軸,並使用該名稱將 .gallery__progress 連結至該時間軸。

如要在元素上建立具名的捲動進度時間軸,請將捲動容器的 scroll-timeline-name CSS 屬性設為您喜歡的值。值必須以 -- 開頭。

由於圖庫會水平捲動,因此您也需要設定 scroll-timeline-axis 屬性。允許的值與 scroll()<axis> 引數相同。

最後,如要將動畫連結至捲動進度時間軸,請將需要動畫效果的元素上的 animation-timeline 屬性,設為與 scroll-timeline-name 所用 ID 相同的值。

  • 變更 styles.css 檔案,加入以下內容:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: --gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: --gallery-is-scrolling;
}

驗證變更

如果一切順利,您現在應該會看到以下內容:

如果沒有,請查看程式碼的 solution-step-2 分支。

6. 在圖片進入和離開捲動檢視區時加入動畫效果

設定匿名檢視進度時間軸

建議您新增淡入效果,讓圖片在進入檢視畫面時淡入。如要查看進度,可以使用「查看進度時間軸」。

如要建立「查看進度時間軸」,可以使用 view() 函式。可接受的引數為 <axis><view-timeline-inset>

  • <axis> 與捲動進度時間軸中的相同,用於定義要追蹤的軸。
  • 使用 <view-timeline-inset> 時,您可以指定偏移 (正值或負值),在系統判斷元素是否在檢視區塊中時調整界線。
  • 關鍵影格已就位,因此您只需要附加即可。如要這麼做,請在每個 .gallery__entry 元素上建立「查看進度時間軸」。

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

限制「觀看進度時間軸」的範圍

如果您儲存 CSS 並載入網頁,會看到元素淡入,但似乎有問題。元素完全不在檢視區塊中時,不透明度為 0,完全離開檢視區塊時,不透明度才為 1

這是因為「檢視進度時間軸」的預設範圍是完整範圍。這就是所謂的cover範圍。

  1. 如要只鎖定主體的 entry 範圍,請使用 animation-range CSS 屬性,限制動畫的執行時間。

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

動畫現在會從 entry 0% (主體即將進入捲軸) 執行到 entry 100% (主體已完全進入捲軸)。

可用的時間軸範圍如下:

  • cover。代表檢視進度時間軸的完整範圍。
  • entry:代表主方塊進入檢視畫面進度可見範圍的期間。
  • exit。代表主方塊退出檢視畫面進度顯示範圍的範圍。
  • entry-crossing:代表主方塊跨越結尾邊界邊緣的範圍。
  • exit-crossing。代表主方塊跨越起始邊界邊緣的範圍。
  • contain。代表主方塊完全包含在捲動埠的檢視區塊進度可見度範圍內,或完全涵蓋該範圍的時間範圍。這取決於主體是否高於或低於捲軸。

使用 https://goo.gle/view-timeline-range-tool 的工具,瞭解每個範圍代表的意義,以及百分比如何影響開始和結束位置。

  1. 由於這裡的開始和結束範圍相同,且使用預設位移,因此請將 animation-range 簡化為單一動畫範圍名稱:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • 如要讓圖片在離開捲動器時淡出,請執行與淡入動畫相同的操作,但指定不同的範圍。

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

系統會將 animate-in 主要畫面格套用至 entry 範圍,並將 animate-out 主要畫面格套用至 exit 範圍。

驗證變更

如果一切順利,您現在應該會看到以下內容:

如果沒有,請查看程式碼的 solution-step-3 分支。

7. 使用一組主要畫面格,在圖片進入和離開捲動檢視區時加入動畫效果

一組關鍵影格的案例

您可以建立一組已包含範圍資訊的關鍵影格,不必為不同範圍附加兩個動畫。

關鍵影格的形狀如下所示:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. 將淡入和淡出主要畫面格合併,如下所示:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. 如果關鍵影格中含有範圍資訊,就不必再另外指定 animation-range。將主要畫面格附加為 animation 屬性。

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

驗證變更

如果一切順利,您應該會得到與上一個步驟相同的結果。如果沒有,請查看程式碼的 solution-step-4 分支。

8. 恭喜!

您已完成本程式碼研究室,現在瞭解如何在 CSS 中建立捲動進度時間軸和檢視區塊進度時間軸!

瞭解詳情

資源: