
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 提供的靈活度將更勝一籌。