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

1. 事前準備

捲動驅動的動畫,可根據捲動容器的捲動位置控制動畫的播放。也就是說,當您向上或向下捲動時,動畫會向前或向後滑動。此外,透過捲動式動畫,您也可以根據元素在捲動容器中的位置控制動畫。這可讓你建立有趣的效果,例如視差背景圖片、捲動進度列,以及會在進入檢視畫面時顯示的圖片。

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

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

課程內容

  • 如何在 CSS 中使用捲動時間軸建立視差背景效果。
  • 如何在 CSS 中使用捲動時間軸建立進度列。
  • 如何使用 CSS 中的檢視畫面時間軸功能製作圖片顯示效果。
  • 如何在 CSS 中指定不同類型的檢視畫面時間軸範圍。

軟硬體需求

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

  • ChromeOS、macOS 或 Windows 上的最新版 Chrome(115 以上版本),並提供「實驗性 Web Platform 功能」旗標已設為 enabled
  • 基本的 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 動畫加入主體元素。其 animation-duration 屬性設為 1 秒,並使用 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);
}

由於根捲動器也是最靠近主體元素的父項捲動器,因此您也可以使用 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 採用絕對位置,因此決定其位置的第一個父項元素是套用 position: relative.gallery 元素。也就是說,系統不會在進行自動查詢時考量 .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 中建立捲動進度時間軸和查看進度時間軸!

瞭解詳情

資源: