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

1. 事前準備

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

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

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

課程內容

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

軟硬體需求

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

  • 在 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% 開始增加,直到下滑條滑到底為止。

查看進度時間軸

這類時間軸會連結至捲動容器中特定元素的相對進度。就像捲動進度時間軸一樣,系統會追蹤捲軸的捲動偏移量。與捲動進度時間軸不同,此時間軸會根據主體在捲動器中的相對位置決定進度。這與 IntersectionObserver 相似,後者會追蹤元素在捲動器中顯示的比例。如果元素在捲軸中沒有顯示,表示兩者並未重疊。如果在捲軸中顯示,即使是最小的部分也是如此,就表示兩者重疊。

檢視進度時間軸會從主體開始與捲動條交錯的瞬間開始,並在主體停止與捲動條交錯時結束。請注意,在下方示意圖中,當主體進入捲動容器時,進度會從 0% 開始計數,並在主體離開捲動容器時達到 100%。

根據預設,連結至「View Progress」時間軸的動畫會連結至整個時間軸範圍。從主體進入捲動區的瞬間開始,到主體離開捲動區為止。

您也可以指定要附加的範圍,將其連結至「觀看進度時間軸」的特定部分。例如,只有在主體進入捲軸時才會發生這種情況。在下列示意圖中,當主體進入捲動容器時,進度會從 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. 現在,請將這些主要畫面格附加至 body 元素:

src/styles.css

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

透過這段程式碼,系統會將 move-background 動畫新增至 body 元素。其 animation-duration 屬性設為 1 秒,並使用 linear 緩動效果。

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

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

<scroller> 引數可接受的值如下:

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

<axis> 引數可接受的值如下:

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

如要將動畫連結至區塊軸上的根捲動器,請將 rootblock 傳遞至 scroll()。將這些值組合起來,即可得到 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 是絕對定位,因此決定其位置的第一個父項元素是 .gallery 元素,因為該元素已套用 position: relative。也就是說,在自動查詢期間,系統不會考慮 .gallery__scrollcontainer 元素 (也就是需要指定的捲動器)。

如要解決這個問題,請在 .gallery__scrollcontainer 元素上建立名為 Scroll Progress Timeline 的時間軸,然後使用該名稱將 .gallery__progress 連結至該時間軸。

如要在元素上建立名為「Scroll Progress Timeline」的時間軸,請將捲動容器上的 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 Progress 時間軸

您可以加入一個不錯的效果,讓圖庫圖片在顯示時淡入。您可以使用「View Progress Timeline」(檢視進度時間軸) 來達成這項目標。

如要建立 View Progress Timeline,您可以使用 view() 函式。可接受的引數為 <axis><view-timeline-inset>

  • <axis> 與捲動進度時間軸相同,可定義要追蹤的軸。
  • 使用 <view-timeline-inset> 時,您可以指定偏移值 (正值或負值),藉此調整元素是否在檢視區域內的邊界。
  • 關鍵影格已就定位,您只需附加即可。如要這麼做,請在每個 .gallery__entry 元素上建立 View Progress Timeline。

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);
}

限制 View Progress 時間軸的範圍

如果您儲存 CSS 並載入網頁,您會看到元素淡入,但似乎有點不對勁。當元素完全離開畫面時,它們會從不透明度 0 開始,且只有在完全離開畫面時才會變成不透明度 1

這是因為 View Progress Timeline 的預設範圍是完整範圍。這就是 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 keyframes 會套用至 entry 範圍,而 animate-out keyframes 會套用至 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 中建立捲動進度時間軸和檢視進度時間軸!

瞭解詳情

資源: