搜尋

CSS 動畫進度控制 animation-timeline、view-timeline、animation-range

雖然實作 CSS 動畫通常都需要手動設定「進度百分比」,但目前已有部分瀏覽器支援「視窗可視位置」以及「瀏覽器卷軸」控制動畫進度的功能,這篇教學會介紹運用 CSS 的 animation-timeline、view-timeline 和 animation-range 樣式屬性,實現進階的動畫進度控制功能。

  • 注意,目前部分瀏覽器不支援這些樣式屬性 ( Firefox、Safari、IE )!
  • 建議先閱讀:CSS 動畫 animation

快速導覽:

CSS 教學 - CSS 動畫進度控制 animation-timeline、view-timeline、animation-range

animation-timeline 動畫進度控制 ( 動畫時間軸 )

animation-timeline 是一個可以「根據畫面或卷軸控制動畫進度」的樣式屬性,會將元素在「可視範圍」裡的位置,或元素所在階層的「視窗捲軸」,當作「時間軸 timeline」,時間軸對應到動畫所設定的進度百分比,就夠單純透過 CSS 讀取這些元素之外數值,在不需要 JavaScript 的輔助下,控制動畫進度,這個樣式沒有繼承特性,具有下列屬性值:

注意,animation-timeline 在 CSS 中的順序必須擺在 animation-name 之後。

屬性值 說明
none 預動畫進度與時間軸無關 ( 預設值 )。
auto 動畫進度自動套用文件時間軸 ( Document.timeline )。
view() 動畫進度使用元素在「可視範圍」中的位置作為時間軸。
scroll() 動畫進度使用畫面卷軸作為時間軸。

animation-timeline: view() 畫面高度

animation-timeline 屬性值裡的 view() 屬於 CSS 函式,支援下列參數數值:

參數 說明
block 邏輯參數,表示垂直方向 ( 預設值,等同 0% 0% )。
inline 邏輯參數,表示水平方向。
y 垂直方向
x 水平方向
start 垂直方向上方 ( 等同 start 0% )
start end 垂直方向上方、垂直方向下方
block start 垂直方向上方、垂直方向下方 ( 等同 start 0% )
block start end 垂直方向上方、垂直方向下方
inline start 左向右書寫模式下,水平方向左側、水平方向右側 ( 等同 inline start 0% )
inline start end 左向右書寫模式下,水平方向左側、水平方向右側

下方的範例會展示使用 view() 屬性值,搭配各種不同參數所呈現的效果,當使用者捲動捲軸時,會看見內容方塊出現變色、尺寸改變的效果,可以注意設定了 startend 的元素,會在指定的位置才發生改變,位置外的樣貌會呈現原本元素的樣式屬性

線上展示:https://codepen.io/oxxo/pen/azbvVrv

<!-- HTML 程式碼 -->
垂直方向改變動畫進度
<div class="out a">
  <div>往下拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>
垂直方向改變動畫進度 ( 限制上 50px 下 100px )
<div class="out b">
  <div>往下拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>
水平方向改變動畫進度
<div class="out c">
  <div>往右拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>
水平方向改變動畫進度 ( 限制左 50px 右 100px )
<div class="out d">
  <div>往右拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  .out {
    width: 300px;
    height: 200px;
    overflow: scroll;      /* 隱藏超出範圍的子元素並出現捲軸 */
    margin: 5px 0 20px 0 ;
    border: 1px solid #000;
  }
  /* 使用一般的 div 撐高畫面,並用漸層背景讓效果更明顯 */
  div:not([class]) {
    width: 400px;
    height: 300px;
    background: repeating-linear-gradient(45deg,#fff 0%,  #fff 5%,#eee 5%, #eee 10%);
  }
  /* 水平捲動的一般 div 高度較小,讓變化的 div 一開始就出現 */
  .c div:not([class]), .d div:not([class]) {height: 100px;}
  /* 動畫進度會改變的 div,注意只使用了動畫名稱而已 */
  .in {
    width: 100px;
    height: 100px;
    background: red;
    animation-name: oxxo; /* 只使用動畫名稱 */
  }
  /* 動畫設定 */
  @keyframes oxxo {
    0% {background: red;}
    25% {background: yellow;}
    50% {background: green;}
    75% {background: blue;}
    100% {
      background: black;
      width: 20px;
      height: 20px;
    }
  }
  .a .in {animation-timeline: view();}            /* 元素在顯示畫面中垂直方向的位置,等同 view(0% 0%) */
  .b .in {animation-timeline: view(50px 100px);}  /* 元素在顯示畫面中垂直方向的位置 */
  .c .in {
    margin: 0 300px;                              /* 讓畫面出現水平捲軸 */
    animation-timeline: view(inline);             /* 元素在顯示畫面中水平方向的位置,等同 view(inline 0% 0%) */
  }
  .d .in {
    margin: 0 300px;                               /* 讓畫面出現水平捲軸 */
    animation-timeline: view(inline 50px 100px );  /* 元素在顯示畫面中水平方向的位置 */
  }
</style>

CSS 教學 - CSS 動畫進度控制- animation-timeline:view() 垂直方向控制動畫進度

CSS 教學 - CSS 動畫進度控制 - animation-timeline:view() 水平方向控制動畫進度

animation-timeline: scroll() 捲軸位置

animation-timeline 屬性值裡的 scroll() 屬於 CSS 函式,支援下列參數數值:

注意,animation-timeline 在 CSS 中的順序必須擺在 animation-name 之後。

參數 說明
block 邏輯參數,表示「最靠近元素且具有捲軸的父層元素」的垂直方向捲軸 ( 預設值,等同 block nearest )。
inline 邏輯參數,表示「最靠近元素且具有捲軸的父層元素」的水平方向捲軸 ( 等同 inline nearest )。
nearest 搭配參數,表示「最靠近元素且具有捲軸的父層元素」的捲軸。
root 搭配參數,「頁面本身的捲軸。
self 搭配參數,元素本身的捲軸。

下方的範例會展示使用 scroll() 屬性值,搭配各種不同參數所呈現的效果,第一組元素會在捲動最靠近元素的父層元素捲軸時發生變化,第二組則是會在捲動頁面捲軸時發生變化,第三組會在捲動元素本身捲軸時發生變化。

線上展示:https://codepen.io/oxxo/pen/gbOaXJo

<!-- HTML 程式碼 -->
最靠近元素的父層元素捲軸
<div class="out a">
  <div>往下拉,觀察變化狀況</div>
  <div class="in">apple<br>banana<br>oxxo<br>coconut<br>papaya</div>
  <div></div>
</div>
網頁文件捲軸
<div class="out b">
  <div>往下拉,觀察變化狀況</div>
  <div class="in">apple<br>banana<br>oxxo<br>coconut<br>papaya</div>
  <div></div>
</div>
元素本身捲軸
<div class="out c">
  <div>往右拉,觀察變化狀況</div>
  <div class="in">apple<br>banana<br>oxxo<br>coconut<br>papaya</div>
  <div></div>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br>


<!-- CSS 程式碼 -->
<style>
  .out {
    width: 300px;
    height: 150px;
    overflow: scroll;      /* 隱藏超出範圍的子元素並出現捲軸 */
    margin: 5px 0 20px 0 ;
    border: 1px solid #000;
  }
  /* 使用一般的 div 撐高畫面,並用漸層背景讓效果更明顯 */
  div:not([class]) {
    background: repeating-linear-gradient(45deg,#fff 0%,  #fff 5%,#eee 5%, #eee 10%);
    width: 400px;
    height: 50px;
  }
  /* 撐高產生捲軸 */
  div:nth-child(3){height: 150px;}
  /* 動畫進度會改變的 div,注意只使用了動畫名稱而已 */
  .in {
    width: 100px;
    height: 100px;
    animation-name: oxxo; /* 動畫名稱 */
    overflow: scroll;     /* 元素本身產生捲軸 */
  }
  /* 動畫設定 */
  @keyframes oxxo {
    0% {background: red;}
    25% {background: yellow;}
    50% {background: green;}
    75% {background: blue;}
    100% {
      background: black;
      width: 20px;
      height: 20px;
    }
  }
  .a .in {animation-timeline: scroll();}     /* 捲動最靠近元素的父層元素捲軸 */
  .b .in {animation-timeline: scroll(root);} /* 捲動頁面捲軸 */
  .c .in {animation-timeline: scroll(self);} /* 捲動元素本身捲軸 */
</style>

CSS 教學 - CSS 動畫進度控制- animation-timeline:scroll() 捲軸控制動畫進度

view-timeline 可視範圍時間軸

view-timeline 是針對 animation-timeline 屬性值為 view() 的延伸樣式屬性,可以設定一組類似 CSS 變數的名稱與數值,接著只要呼叫這個名稱,就能執行和 view() 完全相同的效果,這個樣式是 view-timeline-nameview-timeline-axisview-inset 的縮寫格式,這些樣式屬性都沒有繼承特性,通常只使用 view-timeline 或單純透過 view() 來實現效果

下方範例會將 animation-timeline: view() 的寫法換成 view-timeline,會呈現完全相同的效果,當元素離底部 100px 時就會開始變色變小,值到離頂部 50px 為止。

線上展示:https://codepen.io/oxxo/pen/WbNQXBa

<!-- HTML 程式碼 -->
animation-timeline: view(50px 100px);
<div class="out a">
  <div>往下拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>
view-timeline: --a 50px 100px;<br>
animation-timeline: --a;
<div class="out b">
  <div>往下拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>


<!-- CSS 程式碼 -->
<style>
  .out {
    width: 300px;
    height: 200px;
    overflow: scroll;      /* 隱藏超出範圍的子元素並出現捲軸 */
    margin: 5px 0 20px 0 ;
    border: 1px solid #000;
  }
  /* 使用一般的 div 撐高畫面,並用漸層背景讓效果更明顯 */
  div:not([class]) {
    width: 400px;
    height: 300px;
    background: repeating-linear-gradient(45deg,#fff 0%,  #fff 5%,#eee 5%, #eee 10%);
  }
  /* 動畫進度會改變的 div,注意只使用了動畫名稱而已 */
  .in {
    width: 100px;
    height: 100px;
    background: red;
    animation-name: oxxo; /* 只使用動畫名稱 */
  }
  /* 動畫設定 */
  @keyframes oxxo {
    0% {background: red;}
    100% {
      background: black;
      width: 20px;
      height: 20px;
    }
  }
  .a .in {
    view-timeline: --a 50px 100px;  /* 建立名稱和數值 */
    animation-timeline: --a;        /* 讀取名稱 */
  }
  .b .in {animation-timeline: view(50px 100px);}
</style>

CSS 教學 - CSS 動畫進度控制- view-timeline 可視範圍時間軸

animation-range 動畫執行範圍

animation-range 表示「動畫執行範圍」的樣式屬性,可以針對 view()scroll() 進行數值範圍設定,這個樣式是 animation-range-startanimation-range-end 的縮寫格式,這些樣式屬性都沒有繼承特性,通常只使用 animation-range 來實現效果。

特別注意 animation-range 使用的數值和 view()scroll() 不同,animation-range 的數值表示「元素頂部距離出現位置的距離」

下方會使用 animation-range 代替 view() 的設定,做出更容易理解位置的效果,和下方的另外一組對照組,呈現完全相同的效果。

線上展示:https://codepen.io/oxxo/pen/zxYvPVG

<!-- HTML 程式碼 -->
animation-timeline: view();<br>
animation-range: 50px 150px;
<div class="out a">
  <div>往下拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>
animation-timeline: view(50px 50px);
<div class="out b">
  <div>往下拉,觀察變化狀況</div><div class="in"></div><div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  .out {
    width: 300px;
    height: 200px;
    overflow: scroll;      /* 隱藏超出範圍的子元素並出現捲軸 */
    margin: 5px 0 20px 0 ;
    border: 1px solid #000;
  }
  /* 使用一般的 div 撐高畫面,並用漸層背景讓效果更明顯 */
  div:not([class]) {
    width: 400px;
    height: 300px;
    background: repeating-linear-gradient(45deg,#fff 0%,  #fff 5%,#eee 5%, #eee 10%);
  }
  /* 動畫進度會改變的 div,注意只使用了動畫名稱而已 */
  .in {
    width: 100px;
    height: 100px;
    background: red;
    animation-name: oxxo; /* 只使用動畫名稱 */
  }
  /* 動畫設定 */
  @keyframes oxxo {
    0% {background: red;}
    100% {
      background: black;
      width: 20px;
      height: 20px;
    }
  }
  .a .in {
    animation-timeline: view();   /* 使用可視範圍控制動畫進度 */
    animation-range: 50px 150px;  /* 元素頂部為 50px 開始動畫,值到距離 150px 為止 */
  }
  .b .in {
    animation-timeline: view(50px 50px); /* 出現時 50px,結束值為 300px-250px */
  }
</style>

CSS 教學 - CSS 動畫進度控制- animation-range 動畫執行範圍搭配 view()

對於 view() 而言,animation-range 也可以將上述的數值,搭配下方的屬性值,實現更進階的設定。

屬性值 說明
normal 預設值,按照上述數值控制元素動畫進度。
contain 元素完全被包含在可視範圍中。
cover 元素在可視範圍進入到完全退出的過程。
exit 元素開始退出可視範圍。
exit-crossing 元素開始穿越可視範圍結束邊緣 ( 類似 exit )。
entry 元素開始進入可視範圍。
entry-crossing 元素開始穿越可視範圍起始邊緣 ( 類似 entry )。

下方會使用六個 div,從左到右分別是使用 containcoverexitexit-crossingentryentry-crossing 所呈現的效果,拖拉捲軸後,可以觀察元素進入和離開可視範圍時動畫進度的表現。

線上展示:https://codepen.io/oxxo/pen/VYwvrJb

<!-- HTML 程式碼 -->
<div class="out">
  <div></div>
  <div class="in a"></div>
  <div class="in b"></div>
  <div class="in c"></div>
  <div class="in d"></div>
  <div class="in e"></div>
  <div class="in f"></div>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  .out {
    width: 350px;
    height:250px;
    overflow: scroll;      /* 隱藏超出範圍的子元素並出現捲軸 */
    margin: 5px 0 20px 0 ;
    padding: 20px;
    border: 1px solid #000;  
    background: repeating-linear-gradient(45deg,#fff 0,  #fff 25px,#eee 25px, #eee 50px);
    background-attachment: local;
  }
  /* 使用一般的 div 撐高畫面,並用漸層背景讓效果更明顯 */
  div:not([class]) {
    width: 400px;
    height: 300px;
    clear: both;
  }
  /* 動畫進度會改變的 div,注意只使用了動畫名稱而已 */
  .in {
    width: 40px;
    height: 100px;
    margin: 5px;
    float: left;
    background: red;
    animation-name: oxxo;            /* 動畫名稱 */
    animation-fill-mode: forwards;   /* 動畫結束後停留在最後一格 */
    animation-timeline: view();      /* 使用可視範圍控制動畫進度 */
  }
  /* 動畫設定 */
  @keyframes oxxo {
    0% {background: red;}
    100% {
      background: black;
      height: 200px;
    }
  }
  .a {animation-range: contain;}
  .b {animation-range: cover;}
  .c {animation-range: exit;}
  .d {animation-range: exit-crossing;}
  .e {animation-range: entry;}
  .f {animation-range: entry-crossing;}
</style>

CSS 教學 - CSS 動畫進度控制- animation-range 動畫執行範圍搭配關鍵字屬性值

因為 animation-scroll 無法讀取捲軸移動距離,而透過 animation-range 就能讀取捲軸捲動的數值,透過下拉捲軸的距離控制動畫進度,下方範例會將三個 div 套用不同的 animation-range,執行後將捲軸向下拉動,可以發現三個 div 會在不同高度捲軸時開始執行動畫進度,產生有趣的視覺效果。

線上展示:https://codepen.io/oxxo/pen/jEObajd

<!-- HTML 程式碼 -->
<div class="out">
  <div class="in a"></div>
  <div class="in b"></div>
  <div class="in c"></div>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  .out {
    width: 350px;
    height:250px;
    overflow: scroll;      /* 隱藏超出範圍的子元素並出現捲軸 */
    padding: 20px;
    border: 1px solid #000;  
    background: repeating-linear-gradient(45deg,#fff 0,  #fff 25px,#eee 25px, #eee 50px); /* 用漸層背景讓效果更明顯 */
    background-attachment: local; /* 固定背景 */
  }
  div:not([class]) {
    width: 400px;
    height: 1000px;
    clear: both;
  }
  .in {
    width: 100px;
    height: 100px;
    margin: 5px;
    float: left;
    background: red;
    animation-name: oxxo;          /* 動畫名稱 */
    animation-fill-mode: forwards; /* 動畫結束後停留在最後一格 */
    animation-timeline: scroll();  /* 根據捲軸播放動畫進度 */
  }
  /* 動畫設定 */
  @keyframes oxxo {
    0% {background: red;}
    100% {
      background: black;
      height: 300px;
    }
  }
  .a {animation-range: 10px 100px;}  /* 動畫範圍是捲軸移動的 10px~100px */
  .b {animation-range: 50px 150px;}  /* 動畫範圍是捲軸移動的 50px~150px */
  .c {animation-range: 100px 200px;} /* 動畫範圍是捲軸移動的 100px~200px */
</style>

CSS 教學 - CSS 動畫進度控制- animation-range 動畫執行範圍搭配 scroll()

小結

一但可以透過元素在「可視範圍的位置」或「捲軸位置」控制動畫進度,就更能大幅發揮 CSS 強大的動畫能力,甚至不需要 JavaScript 就能做出許多有趣的捲軸效果,可惜目前還有部分瀏覽器不支援,不過相信這種好用的功能,不久的未來應該會都支援囉。

延伸閱讀:

意見回饋

如果有任何建議或問題,可傳送「意見表單」給我,謝謝~

CSS 教學

基本介紹

認識 CSS 開始使用 CSS CSS 語法規則 CSS 命名原則 CSS 常用樣式屬性

CSS 選擇器

認識 CSS 選擇器 優先順序 ( 權重 ) 樣式繼承與聯集 使用巢狀結構語法 元素選擇器 ID 和 Class 選擇器 屬性選擇器 文件結構選擇器 虛擬類別選擇器 ( 結構 ) 虛擬類別選擇器 ( 類型 ) 虛擬類別選擇器 ( 輸入 ) 虛擬類別選擇器 ( 行為 ) 虛擬類別選擇器 ( 超連結 ) 虛擬類別選擇器 ( 邏輯 ) 虛擬類別選擇器 ( 其他 ) 虛擬元素選擇器 群組與組合選擇器

數值與單位

全域關鍵字與文字數值 長度與角度單位 位置名稱與時間單位 特殊樣式屬性 ( all、appearance)

規則與定義

變數 ( Variables ) 媒體查詢 ( @media ) 容器查詢 ( @container ) 自訂屬性值 ( @property ) 匯入樣式 ( @import ) 分層優先順序 ( @layer ) 定義字型 ( @font-face ) 計數規則 ( @counter-style ) 列印網頁 ( @page )

函式類型

數學計算 文字與清單計數 形狀與線段 路徑 ( path ) 生成內容與引號

顏色與濾鏡

顏色單位 色彩模型 漸層色 影像濾鏡 ( filter ) 背景濾鏡 ( backdrop-filter ) 混合模式 ( mix-blend-mode )

文字與段落

設定字型 ( font-family ) 使用外部字型 文字尺寸 文字樣式 ( 常用 ) 文字樣式 ( 其他實用 ) 文字樣式 ( 特殊用途 ) 文字換行 文字空白與 Tab 大小 文字行高與縮排 文字水平與垂直對齊 文字書寫方向 文字自動分欄

元素容器

容器顯示類型 ( display ) 元素 display 對照表 盒子模型 ( Box Model ) 寬度與高度 內邊距 ( padding ) 外邊界 ( margin ) 邊框 ( border ) 邊框圓角 ( border-radius ) 影像邊框 ( border-image ) 輪廓 ( outline ) 內容溢出與裁切 ( overflow ) 內容範圍 ( contain ) 可見性與透明度

背景與陰影

背景顏色 背景圖 ( 定位、尺寸 ) 背景圖 ( 固定、重複 ) 背景圖 ( 多重背景、混合 ) 背景縮寫 ( background ) 容器陰影 ( box-shadow )

清單與表格

清單樣式 清單計數器 表格基本樣式 表格邊框樣式 表格內容寬度與對齊

基本排版與定位

元素排版方式 浮動 ( float ) 浮動形狀 ( shape-* ) 定位 ( position ) 邏輯屬性 ( logical properties ) 水平置中技巧 垂直置中技巧

Flex 彈性排版

Flexbox 彈性盒子 Flex 對齊方式 Flex 彈性伸縮

Grid 網格排版

Grid 網格容器與格線 Grid 網格空間與命名 Grid 網格流向與間距 Grid 排列網格項目 Grid 項目對齊與順序

轉場與動畫

轉場 ( transition ) 轉場觸發事件 動畫 ( animation ) 自訂動畫路徑 ( offset ) 動畫觸發事件 多重動畫的權重與順序 動畫進度控制 ( timeline )

變形、裁切與遮罩

裁切路徑 ( clip-path ) 影像遮罩 ( mask ) 物件填滿方式與定位 轉換函式 ( transform ) 平移、旋轉與縮放 3D 轉換與透視

視窗與使用者行為

捲軸樣式 ( scrollbar ) 拉霸、滑桿樣式 ( slider ) 滑鼠游標圖示 ( cursor ) 滑鼠事件 ( pointer-events ) 使用者選取 ( user-select ) 捲動行為 ( scroll、overscroll ) 列印換頁 ( break-* )

範例效果

CSS 圓餅圖 CSS 跑馬燈 Google 載入動畫 漸層色的轉場與動畫 電子時鐘數字 不規則形狀動畫 3D 正多面體 超連結底線動畫效果 噁心黏黏球效果 CSS 視差滾動效果 捲軸控制放射形選單 捲軸改變文字背景色 CSS 頁面捲動進度條