/

一個深入的SVG教程

一個深入的SVG教程

SVG是一個令人驚嘆且非常強大的圖像格式。本教程將通過簡單易懂的方式提供SVG的概述,以解釋您需要知道的一切。

簡介

儘管SVG(可縮放矢量圖形)在2000年代初已經定為標準,但它仍然是如今的熱門話題。

多年來,由於瀏覽器的支持(尤其是IE),SVG一直受到懲罰。

我在一本2011年的書中找到了這樣的語句:“在寫作時,將SVG直接嵌入HTML只適用於最新的瀏覽器。”這句話已經過去7年了,現在我們可以安全地使用SVG圖像。

今天,除非您有很多使用IE8及以下版本或舊版Android設備的用戶,否則我們可以安全地使用SVG圖像,此時可使用回退選項。

SVG瀏覽器支持

SVG之所以取得一部分成功,部分原因是我們必須支持各種屏幕顯示器,具有不同的分辨率和尺寸。這是SVG的理想任務。

此外,近年來Flash的急劇衰落,使SVG重新引起人們的興趣,這對於過去Flash完成的許多工作來說是一個很好的選擇。

SVG是一種矢量圖像文件格式。這使它們與PNG、GIF或JPG等光柵圖像文件格式完全不同。

SVG的優勢

由於是矢量圖像,SVG圖像可以進行無限縮放,並且在圖像質量下降方面沒有任何問題。為什麼這樣呢?因為SVG圖像使用XML標記來構建,瀏覽器通過繪製每個點和線而打印它們,而不是使用預定義的像素填充某些空間。這保證了SVG圖像可以適應不同的屏幕尺寸和分辨率,甚至還有尚未發現的尺寸。

由於在XML中定義,SVG圖像比JPG或PNG圖像更靈活,我們甚至可以使用CSS和JavaScript與之交互。SVG圖像甚至可以包含CSS和JavaScript。

SVG圖像可以以比其他格式更小的方式渲染矢量風格圖像,主要用於商標和插圖。另一個巨大的用例是圖標,曾經是FontAwesome之類的圖標字體的範疇,現在設計師更喜歡使用SVG圖像,因為它們更小,並且可以具有多色圖標。

SVG很容易實現動畫效果,這是一個很酷的主題。

SVG提供了一些圖像編輯效果,例如遮罩和裁剪、應用過濾器等。

SVG只是文本,因此可以使用GZip進行高效壓縮。

您的第一個SVG圖像

SVG圖像使用XML進行定義。這意味著,如果您瞭解HTML,則SVG看起來會非常熟悉,只不過,與用於文檔構建(如particlefooteraside)的標籤不同,在SVG中我們有用於矢量圖像構建的基本元素:pathrectline等。

這是一個示例SVG圖像:

1
2
3
<svg width="10" height="10">
<rect x="0" y="0" width="10" height="10" fill="blue" />
</svg>

請注意,它非常容易讀取和理解圖像的外觀:這是一個簡單的10x10像素(默認單位)的藍色矩形。

大多數情況下,您不需要編輯SVG代碼,而是使用諸如Sketch、Figma或任何其他矢量圖形工具來創建圖像,然後導出為SVG。

當前版本的SVG是1.1版本,SVG 2.0版本正在開發中。

使用SVG

可以通過將SVG包含在img標籤中來顯示SVG圖像:

1
<img src="image.svg" alt="My SVG image" />

就像您對其他基於像素的圖像格式所做的那樣:

1
2
3
4
<img src="image.png" alt="My PNG image" />
<img src="image.jpg" alt="My JPG image" />
<img src="image.gif" alt="My GIF image" />
<img src="image.webp" alt="My WebP image" />

此外,非常特別的是,SVG可以直接包含在HTML頁面中:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<title>A page</title>
</head>
<body>
<svg width="10" height="10">
<rect x="0" y="0" width="10" height="10" fill="blue" />
</svg>
</body>
</html>

為了使用減少FOUT(無內容過早渲染),應將CSS放在頂部。

請注意,HTML5和XHTML對內聯SVG圖像需要不同的語法。幸運的是,XHTML已經成為過去,因為它比必要的更複雜,但是如果您仍然需要使用XHTML頁面,這也值得一試。

將SVG內聯在HTML中的能力使這種格式在場景中成為一只獨角獸,其他圖像無法實現這一點,它們必須通過打開單獨的請求來獲取。

SVG元素

在上面的示例中,您看到了對rect元素的使用。SVG具有許多不同的元素。

其中最常用的有:

  • text:創建文本元素
  • circle:創建圓圈
  • rect:創建矩形
  • line:創建直線
  • path:在兩點之間創建路徑
  • textPath:在兩點之間創建路徑和連接的文本元素
  • polygon:可創建任何類型的多邊形
  • g:將多個元素分組

座標從繪圖區域的左上角的0,0開始,x的區域從左到右,y的區域從上到下。

您看到的圖片反映了上面顯示的代碼。使用瀏覽器的DevTools,您可以對其進行檢查和更改。

text

text元素添加文本。可以使用鼠標選擇文本。xy定義文本的起始點。

1
2
3
<svg>
<text x="5" y="30">A nice rectangle</text>
</svg>

circle

定義一個圓。cxcy是圓心坐標,r是半徑。fill是常用的屬性,表示圖形的顏色。

1
2
3
<svg>
<circle cx="50" cy="50" r="50" fill="#529fca" />
</svg>

rect

定義一個矩形。xy是起始座標,widthheight是解釋性的。

1
2
3
<svg>
<rect x="0" y="0" width="100" height="100" fill="#529fca" />
</svg>

line

x1y1定義起始座標,x2y2定義結束座標。stroke是常用的屬性,表示線條的顏色。

1
2
3
<svg>
<line x1="0" y1="0" x2="100" y2="100" stroke="#529fca" />
</svg>

path

路徑是一系列線條和曲線。它是使用SVG繪制的最強大的工具,因此也是最複雜的。

d包含指示命令。這些命令以命令名開始,然後是一組坐標:

  • M表示移動,接受一組坐標x,y
  • L表示線段,接受一組坐標x,y進行線段繪製
  • H是水平線,僅接受一個x坐標
  • V是垂直線,僅接受一個y坐標
  • Z表示關閉路徑,將線返回到起點
  • A表示弧形,它需要一個完整的自己的教程
  • Q是一個二次貝塞爾曲線,同樣需要一個完整的自己的教程
1
2
3
4
5
6
7
8
<svg height="300" width="300">
<path
d="M 100 100 L 200 200 H 10 V 40 H 70"
fill="#59fa81"
stroke="#d85b49"
stroke-width="3"
/>
</svg>

textPath

在路徑元素的形狀上添加文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<svg
viewBox="0 0 1000 600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path id="MyPath" d="M 20 40 Q 260 240 400 500" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="#59fa81" />
<text font-family="Courier New" font-size="42.5">
<textPath xlink:href="#MyPath">
Wow such a nice SVG tut
</textPath>
</text>
</svg>

polygon

使用polygon繪製任意的多邊形。points表示多邊形應該連接的一組x、y坐標:

1
2
3
<svg>
<polygon points="9.9, 1.1, 3.3, 21.78, 19.8, 8.58, 0, 8.58, 16.5, 21.78" />
</svg>

g

使用g元素可以分組多個元素:

1
2
3
4
5
6
7
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="100" fill="#529fca" />
<g id="my-group">
<rect x="0" y="100" width="100" height="100" fill="#59fa81" />
<rect x="100" y="0" width="100" height="100" fill="#ad4a3d" />
</g>
</svg>

SVG視口和viewBox

相對於其容器,SVG的大小由svg元素的widthheight屬性設置。這些單位默認為像素,但您可以使用任何其他常用單位,例如em。這就是視口

一般來說,“容器”表示瀏覽器窗口,但是svg元素可以包含其他svg元素,此時容器是父級svg

一個重要的屬性是viewBox,它允許您在SVG畫布內部定義一個新的座標系統。

假設您有一個簡單的圓,位於200x200像素的SVG中:

1
2
3
<svg width="200" height="200">
<circle cx="100" cy="100" r="100" fill="#529fca" />
</svg>

通過指定viewBox,您可以選擇僅顯示此SVG的一部分。例如,您可以從點0,0開始,僅顯示100x100像素的畫布:

1
2
3
<svg width="200" height="200" viewBox="0 0 100 100">
<circle cx="100" cy="100" r="100" fill="#529fca" />
</svg>

如果從100,100開始,您將看到另一個部分,即圓的右下角:

1
2
3
<svg width="200" height="200" viewBox="100 100 100 100">
<circle cx="100" cy="100" r="100" fill="#529fca" />
</svg>

一個偉大的方式來可視化這一點是想象谷歌地圖是一個巨大的SVG圖像,而您的瀏覽器是一個視口,大小與窗口大小一樣。當您移動時,視口的開始點(x,y)坐標發生變化,當您調整窗口大小時,視口的寬度和高度也會發生變化。

在Web頁面中插入SVG

有多種方法可以將SVG添加到Web頁面中。

最常見的方法包括:

  • 使用img標籤
  • 使用CSS的background-image屬性
  • 內聯在HTML中
  • 使用objectiframeembed標籤

可以在Glitch上查看所有這些示例:https://glitch.com/edit/#!/flavio-svg-loading-ways

使用img標籤

1
<img src="flag.svg" alt="Flag" />

使用CSS的background-image屬性

1
2
3
4
5
6
7
8
<style>
.svg-background {
background-image: url(flag.svg);
height: 200px;
width: 300px;
}
</style>
<div class="svg-background"></div>

內聯在HTML中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<svg
width="300"
height="200"
viewBox="0 0 300 200"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<title>Italian Flag</title>
<desc>By Flavio Copes https://flaviocopes.com</desc>
<g id="flag">
<rect fill="green" x="0" y="0" width="100" height="200"></rect>
<rect fill="white" x="100" y="0" width="100" height="200"></rect>
<rect fill="red" x="200" y="0" width="100" height="200"></rect>
</g>
</svg>

使用objectiframeembed標籤

1
2
3
4
5
<object data="flag.svg" type="image/svg+xml"></object>

<iframe src="flag.svg" frameborder="0"></iframe>

<embed src="flag.svg" type="" />

使用embed,您可以使用以下代碼從父文檔中獲取SVG文檔:

1
document.getElementById('my-svg-embed').getSVGDocument()

從SVG內部您可以使用以下代碼引用父文檔:

1
window.parent.document

如果SVG使用img標籤加載,或將其作為背景使用CSS,則無論起源如何:

  • CSS和JavaScript無法與之交互
  • SVG中的JavaScript被禁用
  • 無法加載圖像、樣式表、腳本、字體等外部資源

詳情


功能 內聯SVG object/embed/iframe img
可與用戶交互
支持動畫
可以運行自己的JavaScript
可以從外部腳本進行操作

在HTML中內嵌的SVG圖像絕對是最強大和靈活的方式,這也是執行某些SVG操作的唯一方式。

如果需要使用imgobjectembed載入SVG,則僅當不需要與之交互時,只需在頁面中顯示它,這將非常方便,尤其是如果在不同的頁面中重複使用SVG圖像,或者SVG大小非常大。

SVG內部的CSS

將CSS放在CDATA中:

1
2
3
4
5
6
7
8
<svg>
<style>
<![CDATA[
#my-rect { fill: blue; }
]]>
</style>
<rect id="my-rect" x="0" y="0" width="10" height="10" />
</svg>

SVG文件中還可以包含外部樣式表:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width=".."
height=".."
viewBox=".."
>
<rect id="my-rect" x="0" y="0" width="10" height="10" />
</svg>

SVG內部的JavaScript

您可以首先放置JavaScript,並在load事件中對其進行封裝,以在頁面完全加載並將SVG插入到DOM時執行它:

1
2
3
4
5
6
<svg>
<script>
<![CDATA[ window.addEventListener("load", () => { //... }, false) ]]>
</script>
<rect x="0" y="0" width="10" height="10" fill="blue" />
</svg>

或者,如果您將JS放在其他SVG代碼末尾,以確保JavaScript在頁面上出現SVG時運行:

1
2
3
4
5
6
<svg>
<rect x="0" y="0" width="10" height="10" fill="blue" />
<script>
<![CDATA[ //... ]]>
</script>
</svg>

就像html標籤一樣,SVG元素也可以具有idclass屬性,因此可以使用選擇器API將它們引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<svg>
<rect
x="0"
y="0"
width="10"
height="10"
fill="blue"
id="my-rect"
class="a-rect"
/>
<script>
<![CDATA[
console.log(document.getElementsByTagName("rect"));
console.log(document.getElementById("my-rect"));
console.log(document.querySelector(".a-rect"));
console.log(document.querySelectorAll(".a-rect"));
]]>
</script>
</svg>

在SVG中查看此功能的示例,可以參考這個Glitch項目:https://glitch.com/edit/#!/flaviocopes-svg-script

SVG外部的JavaScript

如果可以與SVG交互(SVG在HTML中內聯),則可以使用JavaScript更改任何SVG屬性,例如:

1
document.getElementById("my-svg-rect").setAttribute("fill", "black");

或者任何其他DOM操作。

SVG外部的CSS

您可以使用CSS更改SVG圖像的任何樣式。

SVG屬性可以在CSS中輕松覆蓋,它們對CSS具有較低的優先級。它們的行為不像內聯CSS,後者的優先級更高。

1
2
3
4
5
6
7
8
<style>
#my-rect {
fill: red;
}
</style>
<svg>
<rect x="0" y="0" width="10" height="10" fill="blue" id="my-rect" />
</svg>

SVG vs Canvas API

Canvas API是Web平臺的一個重要功能,它與SVG具有類似的瀏覽器支持。它與SVG的主要(且差距很大)區別在於Canvas不是基於矢量的,而是基於像素的,因此:

  • 它具有與像素為基礎的PNG、JPG和GIF圖片格式相同的縮放問題
  • 它使得不可能像SVG那樣使用CSS或JavaScript編輯Canvas圖像

SVG符號

符號允許您定義一次SVG圖像,並在多個位置重用它。如果需要重複使用圖像,甚至只需稍微更改一下某些屬性,這將非常有幫助。

要這樣做,請添加一個symbol元素並分配一個id屬性:

1
2
3
4
5
<svg class="hidden">
<symbol id="rectangle" viewBox="0 0 20 20">
<rect x="0" y="0" width="300" height="300" fill="rgb(255,159,0)" />
</symbol>
</svg>
1
2
3
4
5
6
7
<svg>
<use xlink:href="#rectangle" href="#rectangle" />
</svg>

<svg>
<use xlink:href="#rectangle" href="#rectangle" />
</svg>

xlink:href是為了支持Safari,即使它是一個已棄用的屬性)

這開始展示了SVG的功能。

如果要將這兩個矩形以不同的樣式樣式化,例如使用不同的顏色?您可以使用CSS變量

1
2
3
4
5
<svg class="hidden">
<symbol id="rectangle" viewBox="0 0 20 20">
<rect x="0" y="0" width="300" height="300" fill="var(--color)" />
</symbol>
</svg>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<svg class="blue">
<use xlink:href="#rectangle" href="#rectangle" />
</svg>

<svg class="red">
<use xlink:href="#rectangle" href="#rectangle" />
</svg>

<style>
svg.red {
--color: red;
}
svg.blue {
--color: blue;
}
</style>

參考這個Glitch Playground上的相關示例:https://glitch.com/edit/#!/flavio-svg-symbols

驗證SVG

由於SVG是XML,因此可以以無效的格式來編寫它,某些服務或應用程序可能無法接受無效的SVG文件。

可以使用W3C驗證器來驗證SVG文件。

是否應該包含xmlns屬性?

有時SVG被定義為

1
2
3
<svg>
...
</svg>

有時候是

1
2
3
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
...
</svg>

第二種形式是XHTML。它也可以與HTML5(具有<!DOCTYPE html>的文檔)一起使用,但在這種情況下,第一種形式更簡單。

是否需要擔心瀏覽器支持?

如今,絕大多數用戶的瀏覽器都支持SVG。

您可以使用像Modernizr這樣的庫來檢查缺少的支持並提供回退選項。

if (!Modernizr.svg) {
    document.querySelector(".my-svg").setAttribute("src", "images/logo.png");
}