新視野行銷企劃

SVG 向量圖的結構與可互動特性

扁平化風格網頁封面圖,主題為 SVG 向量圖的結構與可互動特性,展示瀏覽器介面中含有 SVG 圖形與互動操作的設計構成,色調現代且富有科技感。
SVG 圖像就像為網頁插上一幅可縮放的畫布,無論放大縮小都能保持銳利清晰。對於前端開發者來說,SVG(Scalable Vector Graphics,可縮放向量圖形)不僅僅是靜態的圖案,而是可以與 HTML 元素一樣被操控、被賦予互動效果的素材。
從描繪簡單的幾何形狀,到為圖像添加滑鼠懸停變色、點擊動畫等互動,本篇教學將深入介紹 SVG 向量圖的結構 與 可互動特性。透過一系列範例代碼,我們將一步步搭建出會動會響應的 SVG 圖像,並解釋背後的原理。最後在「問與答」單元,會解答幾個開發者常見的疑惑。準備好了嗎?讓我們開始探索 SVG 的世界吧!

SVG 基本語法與結構

在開始動手互動之前,我們先了解 SVG 圖像的結構。SVG 檔案本質上是 XML 格式的程式碼,可以獨立存為 .svg 檔或直接嵌入在 HTML 文件中。每個 SVG 的核心是 <svg> 根元素,我們通常會為它指定明確的寬度、高度,例如:

width 和 height: 定義 SVG 圖像在頁面上的顯示尺寸(預設單位是像素 px)。

(可選)viewBox: 定義內部座標系統及其與外部顯示尺寸的對應關係,如 viewBox="0 0 200 150" 表示內部座標從 (0,0) 到 (200,150)。設定 viewBox 可以讓 SVG 在不同解析度下自適應縮放。

xmlns: XML 名稱空間宣告(通常為 http://www.w3.org/2000/svg),若直接在 HTML5 中使用 <svg> 可以省略,瀏覽器會自動套用正確的名稱空間。

常見 SVG 元素與屬性

在 <svg> 容器內,我們使用各種子元素來繪製圖形。以下列出一些常見的 SVG 標籤(元素)及其用途:

<rect>(矩形): 用於繪製矩形或正方形。主要屬性有 x、y(左上角座標)、width、height(寬高),以及可選的 rx、ry(圓角半徑)來繪製圓角矩形。

<circle>(圓形): 用於繪製圓形。使用 cx、cy 定義圓心座標,r 定義半徑。

<ellipse>(橢圓形): 用於繪製橢圓。使用 cx、cy 定義中心,rx、ry 定義橫向與縱向半徑。

<line>(直線): 繪製一直線,使用 x1、y1 和 x2、y2 定義線段的起點與終點座標。

<polyline>(折線): 繪製由多個線段連接而成的開放折線,用 points 屬性定義一串頂點座標。

<polygon>(多邊形): 繪製封閉的多邊形圖形,points 屬性定義頂點座標,最後一個頂點會自動連回第一個頂點形成封閉圖形。

<path>(路徑): 繪製任意複雜的路徑或形狀。使用 d 屬性來描述路徑指令,例如 M10 10 L100 10 L100 100 Z 代表從 (10,10) 移動到 (100,10) 再到 (100,100),最後閉合路徑,可繪製出一個三角形。<path> 是功能最強大的繪圖元素,可繪製曲線、弧形等各種圖案。

<text>(文字): 在 SVG 中呈現文字。使用 x、y 指定文字起始座標,並可用 font-size、fill 等屬性設定文字大小和顏色。另有 text-anchor 等屬性可以控制對齊方式,例如 text-anchor="middle" 可讓文字水平對齊於給定的 x 座標中點。

<g>(群組): 並非繪製特定圖形,而是將若干圖形元素包裹成一個群組。群組可以統一調整樣式或變形(例如平移、縮放整組圖形),對複雜圖像的管理非常有用。

上述元素大都可以透過屬性來設定樣式,比如:

fill: 填色,指定圖形內部的顏色(例如 fill="red" 或 fill="#FF0000")。若填色為 none 則表示透明(不填滿)。

stroke: 描邊顏色,即圖形邊框線條的顏色。

stroke-width: 描邊線條的寬度(粗細)。

以及其他屬性如 opacity(不透明度)、stroke-dasharray(虛線樣式)等。

值得注意的是,SVG 的繪製順序會影響圖形的疊放層級:後定義的元素會覆蓋在先定義的元素之上。接下來,我們用一個簡單範例來說明上述語法如何實際繪製圖形。請參考以下範例程式碼:

<svg width="200" height="150">
  <!-- 畫一個覆蓋整個區域的矩形作為背景 -->
  <rect width="100%" height="100%" fill="#F0E68C" />
  <!-- 在中央畫一個橙色圓形,半徑為50,有黑色邊框 -->
  <circle cx="100" cy="75" r="50" fill="orange" stroke="black" stroke-width="3" />
  <!-- 在圓形中央加入文字 -->
  <text x="100" y="85" font-size="30" text-anchor="middle" fill="black">SVG</text>
</svg>

上述程式碼產生了一個 200×150 像素的 SVG 區域。我們首先繪製了一個淺卡其色(#F0E68C)的矩形作為背景,width="100%" height="100%" 使其覆蓋整個繪圖區域(SVG 座標系統的原點在左上角,因此該矩形從 (0,0) 起始填滿背景)。接著程式碼繪製一個橙色的圓形,其圓心座標為 (cx=100, cy=75)、半徑 r=50,並設定黑色邊框及 3 像素的描邊粗細。由於此圓形定義在矩形之後,顯示時會疊蓋在背景矩形上方。

最後,我們使用 <text> 標籤在圓形中央加入文字 "SVG"。x=100 搭配 text-anchor="middle" 使文字水平居中對齊於 x 座標 100(也就是圓心的垂直中線上),y=85 則略微調整文字基線的位置以在視覺上接近圓形的垂直中心。因文字元素被定義在圓形之後,所以文字會顯示在圓形上方。透過這個簡單範例,我們可以清楚看到前述 SVG 結構:從容器大小設定,到基本形狀與文字標籤,以及填色、描邊等樣式的應用。

使用 HTML/CSS/JS 讓 SVG 活動起來

靜態的 SVG 圖像固然清晰,但在現代網頁中,光有靜態內容往往不足以吸引用戶。我們可以利用 HTML、CSS 和 JavaScript 來操控 SVG 元素,讓它們對使用者的操作做出反應。由於嵌入 HTML 的 SVG 元素其實也是 DOM(Document Object Model,文件物件模型) 的一部分,因此我們可以像操作一般 HTML 標籤一樣,透過 CSS 改變樣式,或用 JS 綁定事件監聽器來改變 SVG 的屬性。

CSS 樣式與滑鼠懸停效果

首先,CSS 可以直接套用在 SVG 元素上。例如,我們可以為 SVG 中的形狀設定 :hover 偽類,在滑鼠移到圖形上時改變其樣式。只要該 SVG 內的元素有對應的選擇器(例如有特定的 class 或 id),寫起來和一般 CSS 沒兩樣。甚至我們可以在 SVG 定義內部使用 <style> 標籤嵌入 CSS 樣式。常見的做法包括改變填色 (fill)、不透明度 (opacity)、或是利用 transform 做簡單的縮放效果,在懸停時突出顯示。

JavaScript 事件與屬性操作

再來,JavaScript 提供了更彈性的互動控制。我們可以透過 document.getElementById() 或 querySelector() 抓取 SVG 裡的元素節點,並使用 addEventListener() 為它們添加各種事件監聽,例如 click 點擊、mouseenter/mouseleave 滑鼠進出等。當事件被觸發時,透過 JavaScript 改變該元素的屬性或樣式,就能立即反映在畫面上。例如改變圓形的 cx 讓它移動位置,或修改 fill 讓它變換顏色。

讓我們通過一個完整範例,來結合上述概念。以下代碼建立了一個簡單的 SVG 圖形(藍色圓形),並展示兩種互動效果:滑鼠懸停時圓形變色,點擊時圓形向右移動:

<svg width="300" height="150">
  <circle id="ball" cx="50" cy="75" r="20" fill="blue" />
</svg>

<style>
  /* 讓圓形在顏色變化時平滑過渡 */
  #ball {
    transition: fill 0.3s;
  }
  /* 滑鼠懸停時改變圓形填色,並變換游標樣式以提示可點擊 */
  #ball:hover {
    fill: orange;
    cursor: pointer;
  }
</style>

<script>
  // 取得圓形元素,並綁定點擊事件監聽器
  const ball = document.getElementById('ball');
  ball.addEventListener('click', () => {
    // 每次點擊時,將圓心的 x 座標往右移動 50 單位
    const currentX = parseFloat(ball.getAttribute('cx'));
    ball.setAttribute('cx', currentX + 50);
  });
</script>

上述範例在 HTML 頁面中嵌入了一個寬 300、高 150 的 SVG,其中只有一個 id 為 "ball" 的藍色圓形。CSS 部分,我們對 #ball 設定了 transition: fill 0.3s,讓填色變化具有 0.3 秒的平滑過渡效果;並定義了 #ball:hover 狀態,在滑鼠懸停時將填色改為橘色 (orange),同時將游標樣式變為指針狀(通常表示此元素可點擊)。

接著在 JavaScript 部分,我們透過 getElementById('ball') 選取到該圓形元素,然後對它附加了一個 'click' 點擊事件監聽器。當使用者點擊圓形時,會執行我們提供的箭頭函式:首先使用 getAttribute('cx') 取得目前圓心的 x 座標值,並用 parseFloat 將其轉成數值,接著將新的座標值設定回 cx(原本的值加上 50)。如此一來,每點擊一次圓形,它的 cx 就會增加 50,圓形看起來便向右平移了 50px。

(註:此範例為了說明方便,直接將 <style> 和 <script> 寫在 HTML 中靠近 SVG 的位置。在實際開發時,可以將 CSS 提取到外部樣式表或 <head> 中,JavaScript 則放到頁面底部或獨立檔案,以保持結構清晰。)

SVG 動畫效果

除了被動等待使用者操作,我們也可以讓 SVG 元素主動地動起來。實現動畫的方式有很多種,開發者可以視需求選擇:

CSS 動畫: 利用 CSS transition 或 @keyframes,可以對 SVG 元素的屬性(如位置、透明度)進行過渡或關鍵幀動畫。例如使用 @keyframes 定義一個圓形在水平方向來回移動的動畫,並在元素上套用該動畫。CSS 動畫的優點是簡潔,瀏覽器對其進行了優化處理,適合週期性、相對簡單的動畫效果。

SVG SMIL 動畫: SVG 本身支援使用 <animate>、<animateTransform> 等標籤直接在 SVG 定義中聲明動畫(稱為 SMIL 動畫)。例如,可以在 <circle> 裡添加 <animate attributeName="cx" ...> 使其自動改變位置。這種方式直觀,但需要注意瀏覽器相容性(現代瀏覽器大多支援,但曾一度不鼓勵使用)。

JavaScript 控制: 透過 JavaScript,我們可以精細地掌控動畫時序和效果,例如使用 setInterval 或更佳的 requestAnimationFrame 來每幀更新屬性。這種方式適合需要複雜邏輯、與使用者互動或非線性時軸的動畫。

下面,我們以 JavaScript requestAnimationFrame 為例,實作一個圓點水平來回移動的動畫。requestAnimationFrame 是瀏覽器提供的 API,用於在瀏覽器準備重繪畫面時調用指定函式,使動畫更新與螢幕刷新同步,能夠提高流暢度和效能。請看以下範例:

<svg width="400" height="120">
  <circle id="dot" cx="20" cy="60" r="10" fill="purple" />
</svg>

<script>
  const dot = document.getElementById('dot');
  let x = 20;
  let direction = 1; // 方向:1 表示向右,-1 表示向左
  function animate() {
    // 更新位置
    x += 2 * direction;
    // 碰到邊界時反轉方向(假設圓心在 20 和 380 之間來回)
    if (x > 380 || x < 20) {
      direction *= -1;
    }
    // 將更新後的位置設定回圓形的屬性
    dot.setAttribute('cx', x);
    // 在下一個動畫幀再次呼叫 animate
    requestAnimationFrame(animate);
  }
  // 啟動動畫
  animate();
</script>

在上述程式中,我們讓半徑為 10 的紫色圓點在水平軸上來回"彈跳"。具體步驟如下:

初始化: 取得 id 為 "dot" 的 <circle> 元素,並設定初始變數 x = 20(初始 cx 坐標)和 direction = 1(初始移動方向向右)。

定義動畫函式: animate() 函式每次呼叫時,都將目前的 x 根據 direction 增加或減少(這裡每幀移動 2 單位)。然後判斷 x 是否超出預定範圍(在本例中我們設定讓圓心在 20 和 380 之間移動,這對應著圓點碰到 SVG 邊緣就折返)。如果超出邊界,我們把 direction 乘以 -1 來反轉移動方向。

更新屬性: 使用 dot.setAttribute('cx', x) 將計算出的新座標值賦予圓點的 cx。如此一來,圓點在畫面中的位置就被更新了。

循環呼叫: 透過 requestAnimationFrame(animate) 讓瀏覽器在下一次重繪前再度執行 animate(),形成連續的動畫循環。requestAnimationFrame 會嘗試以每秒 60 幀左右的頻率執行提供的函式,因此能得到平滑的動畫效果。

打開網頁時,animate() 會立刻被呼叫一次並啟動循環,圓點開始來回移動。如果需要停止動畫,只要在適當條件下不再呼叫 requestAnimationFrame 即可(例如不再調用 animate)。同理,我們也可以在動畫中改變其他屬性,比如 cy 來讓圓點上下跳動,或改變 r 來做尺寸的漸變。

以上例子展示了 JavaScript 控制 SVG 動畫的原理。實務中,我們可以配合使用者操作(例如點擊按鈕開始/停止動畫),或結合複雜的數學函數來實現更華麗的效果。如果是相對簡單的循環動畫,CSS @keyframes 會更為方便;但當動畫需要和使用者互動或流程複雜時,JavaScript 提供的靈活度將更勝一籌。

問與答

問:SVG 與 Canvas 的差異?
答:SVG 基於 XML 標記來描述圖形,每個圖形元素(例如一個矩形、一個圓形)都是瀏覽器 DOM 中的節點,可以獨立設定樣式和監聽事件;Canvas 則是使用 JavaScript 在一個位圖畫布上逐像素繪製,繪製完成後圖形不再以物件形式存在。這帶來幾點差異:首先,SVG 向量圖形具有無損縮放的特性,無論放大縮小都不會失真,而 Canvas 繪製的內容放大後會出現鋸齒或模糊(除非重新繪製更高解析度的版本)。其次,在互動性上,SVG 元素可以直接綁定滑鼠、觸控等事件(如前文所示),而 Canvas 只有整個畫布一個元素,需自行計算座標區域來實現類似的點擊偵測。最後是效能方面:Canvas 更適合即時繪製大量圖形的情境(例如遊戲、粒子特效),因為它直接對像素進行操作;SVG 則適合圖形數量中等、需要高品質縮放和樣式控制的場合(例如圖表、介面圖示)。不過當 SVG 場景中物件過多(成千上萬)時,操作 DOM 可能變得緩慢,因此非常大量且頻繁變化的繪圖還是 Canvas 更有優勢。
問:SVG 能否與其他 JavaScript 函式庫搭配使用?
答:可以的,SVG 與各種 JavaScript 函式庫能良好結合。由於 SVG 元素就是 DOM 節點,任何操作 DOM 或動畫的庫都可以用在 SVG 上。舉例來說,著名的資料視覺化庫 D3.js 就大量運用 SVG 來繪製圖表,透過資料驅動的方式動態生成 SVG 元素。再如 GSAP (GreenSock Animation Platform) 這類強大的動畫庫,也完全支援操控 SVG,能對其屬性做平滑的補間動畫。另外還有 Snap.svg、Paper.js 等專門為 SVG 設計的函式庫,提供便利的 API 來創建和控制 SVG 圖像。在現代前端框架如 React、Vue 中,你也可以直接使用 SVG:要麼在 JSX/模板裡寫 SVG 標籤,或使用套件將 SVG 作為元件引入。因此,無論是繪圖、動畫還是框架整合,SVG 都可以方便地與其他工具配合。
問:可以在 SVG 上實現非常複雜的動畫效果嗎?
答:當然可以。SVG 的動畫潛力非常大——幾乎所有圖形屬性都能通過程式碼來改變,組合起來就能產生豐富的效果。開發者可以手動編寫程式,讓多個 SVG 元素按時間線協調變化,實現分鏡頭般的複雜動畫;甚至可以根據使用者輸入或其他事件來動態改變動畫流程。如果手動實現太繁瑣,可以借助前面提到的動畫函式庫(例如 GSAP)來編排複雜的 SVG 動畫序列,甚至包含形狀變形(morphing)等高級效果。總之,只要瀏覽器性能允許,SVG 上能夠達成的動畫複雜度幾乎沒有上限,開發者可以大膽發揮創意,打造出精美的動畫和互動體驗。

CONTACT US

網站設計報價洽詢

請填寫您的資料,我們將儘快與您聯繫! 為必填