搜尋

自訂 CSS 動畫路徑 offset

如果已經熟悉了 CSS 動畫的基本語法,接下來還能透過一系列 CSS offset 樣式屬性,使用類似 SVG 的 path 路徑繪製獨一無二的動畫路線,這篇教學除會介紹與「自訂動畫路徑」相關的 offset、offset-anchor、offset-distance、offset-path、offset-position 和 offset-rotate 樣式屬性。

閱讀更多:CSS 動畫 animationCSS animation 觸發事件CSS 多重動畫的權重與順序

快速導覽:

CSS 教學 - 自訂動畫路徑 offset

offset-path 動畫路徑

offset-path 表示「設定動畫路徑」的樣式屬性,沒有繼承特性,需要搭配 offset-distance 樣式屬性共同操作,如果沒有使用 offset-distance,位置會一直保持在路徑的起點offset-path 所使用的屬性值為「形狀、線段、路徑」相關的 CSS 函式 ( 點擊函式名稱可以查看詳細教學 ):

CSS 函式 說明
circle() 圓形
ellipse() 橢圓形
rect() 四邊形
polygon() 多邊形
inset() 內縮邊距和圓角
xywh() 虛擬矩形
ray() 放射線形狀
path() 路徑

下方的範例會呈現不同路徑的元素位置 ( 使用同樣路徑的 SVG 放在下方 )。

注意,因為 CSS 的 path() 沒辦法像 SVG 可以透過 viewpoint 縮放,因此在定義路徑時就必須要設定好長寬尺寸。

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

<!-- HTML 程式碼-->
<div class="a">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-miterlimit="10" d="m35 11c-30.1 10.9-41.8 95.7-7 131 34.8 35.3 79 31.6 46 64-33 32.4 101.2 114.2 118 32 16.8-82.2 47.8-158.9-28-136-75.8 22.9-128.6 28.1-82-17 46.6-45.1 14.5-96.3-47-74z"/></svg>
  <div></div>
</div>
<div class="b">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-miterlimit="10" d="m148.9 281.8c-64.5-11.6-95.1-36.8-119.4-88.4-24.3-51.6 5-110.8 53.9-144.8 48.9-34 105.6-37.6 154 8 32 30.1 33.6 80.3 28.9 100-10.8 46-33.7 57.4-62 70-36.7 16.3-76.4 15.6-111.6-21.2-16.5-17.3-23.7-63.6-6.6-90.9 14.2-22.8 56-58.8 87.3-47.9 31.4 11 39.3 29.6 50.6 57.1 9.3 22.7-10.3 48.4-44.2 63.2-34 14.7-58.7-13.3-57-29.3 4.5-41.6 46.4-33.7 46.4-33.7"/></svg>
  <div></div>
</div>
<div class="c">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>
<div class="d">
  <svg viewBox="0 0 300 300"><rect fill="none" stroke="#000" stroke-miterlimit="10" x="50" y="50" rx="20" ry="20" width="200" height="150"/></svg>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 300px;
    height: 300px;
    float: left;
  }
  div {margin:0 -50px -20px 0;}
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 20px;
    height: 20px;
    background: red;
    float: none;
    offset-distance: 50%;  /* 調整後可以觀察位置 */
  }
  /* 自訂路徑 */
  .a div {
    offset-path: path("m35 11c-30.1 10.9-41.8 95.7-7 131 34.8 35.3 79 31.6 46 64-33 32.4 101.2 114.2 118 32 16.8-82.2 47.8-158.9-28-136-75.8 22.9-128.6 28.1-82-17 46.6-45.1 14.5-96.3-47-74z");
  }
  /* 自訂路徑 */
  .b div {
    offset-path: path("m148.9 281.8c-64.5-11.6-95.1-36.8-119.4-88.4-24.3-51.6 5-110.8 53.9-144.8 48.9-34 105.6-37.6 154 8 32 30.1 33.6 80.3 28.9 100-10.8 46-33.7 57.4-62 70-36.7 16.3-76.4 15.6-111.6-21.2-16.5-17.3-23.7-63.6-6.6-90.9 14.2-22.8 56-58.8 87.3-47.9 31.4 11 39.3 29.6 50.6 57.1 9.3 22.7-10.3 48.4-44.2 63.2-34 14.7-58.7-13.3-57-29.3 4.5-41.6 46.4-33.7 46.4-33.7");
  }
  .c div {offset-path: circle(100px at 150px 150px);}             /* 圓形 */
  .d div {offset-path: xywh(50px 50px 200px 150px round 20px); }  /* 矩形 */
</style>

CSS 教學 - 自訂動畫路徑 offset - offset-path 動畫路徑

offset-distance 移動距離

offset-distance 表示「元素在路徑中移動的距離」,沒有繼承特性,只能使用「百分比」作為單位,0% 表示起點,100% 表示末端點,執行順序「必須位於 offset-path 後方」,下方範例會搭配 animation 動畫,讓紅色 div 在不同線段中移動。

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

<!-- HTML 程式碼-->
<div class="a">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-miterlimit="10" d="m35 11c-30.1 10.9-41.8 95.7-7 131 34.8 35.3 79 31.6 46 64-33 32.4 101.2 114.2 118 32 16.8-82.2 47.8-158.9-28-136-75.8 22.9-128.6 28.1-82-17 46.6-45.1 14.5-96.3-47-74z"/></svg>
  <div></div>
</div>
<div class="b">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-miterlimit="10" d="m148.9 281.8c-64.5-11.6-95.1-36.8-119.4-88.4-24.3-51.6 5-110.8 53.9-144.8 48.9-34 105.6-37.6 154 8 32 30.1 33.6 80.3 28.9 100-10.8 46-33.7 57.4-62 70-36.7 16.3-76.4 15.6-111.6-21.2-16.5-17.3-23.7-63.6-6.6-90.9 14.2-22.8 56-58.8 87.3-47.9 31.4 11 39.3 29.6 50.6 57.1 9.3 22.7-10.3 48.4-44.2 63.2-34 14.7-58.7-13.3-57-29.3 4.5-41.6 46.4-33.7 46.4-33.7"/></svg>
  <div></div>
</div>
<div class="c">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>
<div class="d">
  <svg viewBox="0 0 300 300"><rect fill="none" stroke="#000" stroke-miterlimit="10" x="50" y="50" rx="20" ry="20" width="200" height="150"/></svg>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 300px;
    height: 300px;
    float: left;
  }
  div {margin:0 -50px -20px 0;}
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 20px;
    height: 20px;
    background: red;
    float: none;
    animation: oxxo 2s infinite alternate; /* 執行動畫 */
  }
  .a div {
    offset-path: path("m35 11c-30.1 10.9-41.8 95.7-7 131 34.8 35.3 79 31.6 46 64-33 32.4 101.2 114.2 118 32 16.8-82.2 47.8-158.9-28-136-75.8 22.9-128.6 28.1-82-17 46.6-45.1 14.5-96.3-47-74z");
  }
  .b div {
    offset-path: path("m148.9 281.8c-64.5-11.6-95.1-36.8-119.4-88.4-24.3-51.6 5-110.8 53.9-144.8 48.9-34 105.6-37.6 154 8 32 30.1 33.6 80.3 28.9 100-10.8 46-33.7 57.4-62 70-36.7 16.3-76.4 15.6-111.6-21.2-16.5-17.3-23.7-63.6-6.6-90.9 14.2-22.8 56-58.8 87.3-47.9 31.4 11 39.3 29.6 50.6 57.1 9.3 22.7-10.3 48.4-44.2 63.2-34 14.7-58.7-13.3-57-29.3 4.5-41.6 46.4-33.7 46.4-33.7");
  }
  .c div {offset-path: circle(100px at 150px 150px); }
  .d div {offset-path: xywh(50px 50px 200px 150px round 20px);}

  @keyframes oxxo {
    0% {offset-distance: 0%;}
    100% {offset-distance: 100%;}
  }
</style>

CSS 教學 - 自訂動畫路徑 offset - offset-distance 移動距離

offset-anchor 對齊路徑

offset-anchor 表示「元素如何對齊路徑」,沒有繼承特性,會使用 1~2 個屬性值,定義元素的「對齊點」和「路徑」之間的關係,屬性值支援三種寫法:

下方範例會使用比較粗的線條,呈現這些寫法以及對齊路徑的差異。

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

<!-- HTML 程式碼-->
<div class="a">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="100" d="m22.4 88h244.2z"/></svg><div></div>
</div>
<div class="b">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="100" d="m22.4 88h244.2z"/></svg><div></div>
</div>
<div class="c">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="100" d="m22.4 88h244.2z"/></svg><div></div>
</div>
<div class="d">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="100" d="m22.4 88h244.2z"/></svg><div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 300px;
    height: 200px;
    float: left;
  }
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 50px;
    height: 50px;
    background: #f00a;
    float: none;
    offset-path: path("m22.4 88h244.2z");           /* 使用直線路徑 */
  }
  .a div {offset-anchor: center;}                   /* 中心點對齊路徑起始位置與中線 */
  .b div {offset-anchor: left bottom;}              /* 左下點對齊路徑起始位置與中線  */
  .c div {offset-anchor: 10px 10px;}                /* 左上內縮 10px 10px 對齊路徑起始位置與中線  */
  .d div {offset-anchor: right 20px bottom 50px;}   /* 右下內縮 20px 50px 對齊路徑起始位置與中線  */
</style>

CSS 教學 - 自訂動畫路徑 offset - offset-anchor 對齊筆畫

offset-rotate 旋轉方向

offset-rotate 表示「元素在路徑上的旋轉方向」,沒有繼承特性,有下列幾種屬性值寫法

屬性值 說明
auto 預設值,表示旋轉方向和路徑方向相同。
auto angle 在路徑的方向上額外加上角度 ( 使用角度單位 ),順時針為正。
angle 沿著 X 軸的水平方向為 0deg,完全按照指定角度旋轉 ( 使用角度單位 ),順時針為正。
reverse auto 反轉 180deg,表示旋轉方向和路徑方向相反。
reverse angle 在路徑相反方向上額外加上角度 ( 使用角度單位 ),順時針為正。

下方範例會展示這五種旋轉方向的差異。

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

<!-- HTML 程式碼-->
<div class="a">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="2" d="m22 21l116.5 116.5z"/></svg>
  <div></div>
</div>
<div class="b">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="2" d="m22 21l116.5 116.5z"/></svg>
  <div></div>
</div>
<div class="c">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="2" d="m22 21l116.5 116.5z"/></svg>
  <div></div>
</div>
<div class="d">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="2" d="m22 21l116.5 116.5z"/></svg>
  <div></div>
</div>
<div class="e">
  <svg viewBox="0 0 300 300"><path fill="none" stroke="#000" stroke-width="2" d="m22 21l116.5 116.5z"/></svg>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 300px;
    height: 200px;
    float: left;
    margin: 10px -100px 10px 10px;
  }
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 0;
    height: 0;
    float: none;
    offset-path: path("m22 21l116.5 116.5z");
    border-width: 10px 0 10px 50px;
    border-color: #0000 #0000 #0000 #f00b;
    border-style: solid;
  }
  .a div {offset-rotate: auto}
  .b div {offset-rotate: 45deg;}
  .c div {offset-rotate: auto 45deg;}
  .d div {offset-rotate: reverse;}
  .d div {offset-rotate: reverse 45deg;}
</style>

CSS 教學 - 自訂動畫路徑 offset - offset-rotate 旋轉方向

下方範例使用動畫的方式,呈現 auto 和固定角度的差異。

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

<!-- HTML 程式碼-->
<div class="a">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>
<div class="b">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 300px;
    height: 200px;
    float: left;
    margin: 20px -20px;
  }
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 0;
    height: 0;
    float: none;
    offset-path: circle(100px at 150px 150px);
    border-width: 20px 0 20px 100px;
    border-color: #0000 #0000 #0000 #f00b;
    border-style: solid;
    animation: oxxo 2s infinite linear;
  }
  .a div {offset-rotate: auto;}
  .b div {offset-rotate: 45deg;}
  @keyframes oxxo {
    0% {offset-distance: 0%;}
    100% {offset-distance: 100%;}
  }
</style>

CSS 教學 - 自訂動畫路徑 offset - offset-rotate auto 和固定角度的差異

offset-position 路徑起點位置

offset-position 表示「路徑起點位置」,沒有繼承特性,會使用 1~2 個屬性值定義元素的「起點位置」,目前主要支援 ray() 函式產生的路徑,定義方式如下:

參考:ray() 放射線

下方範例會使用四個 div,呈現這些寫法以及不同起點的差異。

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

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

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 200px;
    height: 200px;
    float: left;
    margin: 50px;
    border: 1px solid #000;
  }
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 50px;
    height: 50px;
    background: #f00a;
    float: none;
    offset-path: ray(30deg);
  }
  .a div {offset-position: normal;}
  .b div {offset-position: right;}
  .c div {offset-position: bottom left;}  
  .d div {offset-position: 30% 30%;}
</style>

CSS 教學 - 自訂動畫路徑 offset - offset-position 路徑起點位置

offset 動畫路徑縮寫格式

offset 表示「動畫路徑的縮寫格式」,沒有繼承特性,是由上述所有的樣式屬性縮寫而成,相關寫法如下:

div {
  offset: offset-path;
  offset: offset-path offset-distance; 
  offset: offset-path offset-distance offset-rotate;
  offset: offset-path offset-distance offset-rotate / offset-anchor; /* offset-anchor 前方要用斜線分隔  */
}

下方範例會使用四個 div 呈現不同的寫法。

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

<!-- HTML 程式碼-->
<div class="a">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>
<div class="b">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>
<div class="c">
  <svg viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>
<div class="d">
  <svg id="s" viewBox="0 0 300 300"><circle fill="none" stroke="#000" stroke-miterlimit="10" cx="150" cy="150" r="100"/></svg>
  <div></div>
</div>

<!-- CSS 程式碼 -->
<style>
  div {
    position: relative;
    width: 300px;
    height: 200px;
    float: left;
    margin: 20px -20px;
  }
  div div {
    top: 0;
    left: 0;
    position: absolute;
    width: 0;
    height: 0;
    float: none;
    border-width: 20px 0 20px 100px;
    border-color: #0000 #0000 #0000 #f00b;
    border-style: solid;
    animation: oxxo 2s infinite linear;
  }
  .a div {offset: circle(100px at 150px 150px);}
  .b div {offset: circle(100px at 150px 150px) 45deg;}
  .c div {offset: circle(100px at 150px 150px) 45deg / left;}
  .d div {offset: circle(100px at 150px 150px) auto 90deg / right;}
  @keyframes oxxo {
    0% {offset-distance: 0%;}
    100% {offset-distance: 100%;}
  }
</style>

CSS 教學 - 自訂動畫路徑 offset - offset 動畫路徑縮寫格式

小結

透過動畫路徑的做法,可以讓原本不容易控制位置的動畫效果,突然變成可以很簡單的操控移動的方向和位置,如果手邊有些 CSS 動畫需要實作,建議可以開始使用自訂動畫路徑的方式,創造出更加吸引眼球的動畫效果。

閱讀更多:CSS 動畫 animationCSS animation 觸發事件CSS 多重動畫的權重與順序

意見回饋

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

CSS 教學

基本介紹

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

CSS 選擇器

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

數值與單位

關鍵字與文字數值 長度與角度單位 位置名稱與時間單位

規則與定義

變數 ( Variables ) 媒體查詢 ( @media ) 容器查詢 ( @container ) 自訂屬性值 ( @property ) 匯入樣式 ( @import ) 分層優先順序 ( @layer )

函式類型

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

顏色與濾鏡

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

文字與段落

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

元素容器

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

背景與陰影

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

清單與表格

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

基本排版與定位

元素排版方式 浮動 ( float ) 浮動形狀 定位 ( position )

Flexbox 彈性排版

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

Grid 網格排版

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

轉場與動畫

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

變形、裁切與遮罩

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

視窗與使用者行為

捲軸樣式 ( scrollbar ) 滑鼠游標圖示 ( cursor ) 滑鼠事件 ( pointer-events ) 使用者選取 ( user-select ) 捲動行為 ( scroll、overscroll )

範例效果

CSS 圓餅圖 CSS 跑馬燈 Google 載入動畫 漸層色的轉場與動畫 電子時鐘數字 不規則形狀動畫