liu, summerqy SVG 優化探索
In 未分類 on 2019年07月31日 by view: 4,733
0

SVG 優化探索

在前端開發中或多或少都有用到 SVG,本篇文章就來總結下如何在前端項目中使用 SVG,每種使用方式的優缺點分析,以及對 SVG 的一些優化探索。

一、認識 SVG

三、SVG 使用方法

四、在 React + Webpack 項目中如何引入 SVG?

五、SVG 優化

一、認識 SVG

SVG(Scalable Vector Graphics,可縮放矢量圖形)是一種基于可擴展標記語言XML),用于描述二維矢量圖形的一種圖形格式。

這里簡要說明下位圖與矢量圖的區別:位圖是由像素點構成的,矢量圖則是由一些形狀元素構成。下圖中放大位圖可以看到點,而放大矢量圖看到的仍然是形狀。SVG 屬于矢量圖,因此理論上能夠無限縮放,而不會導致馬賽克。

image-20190721201713555

簡單的 SVG 樣式:

SVG 的幾大特點:

1)能使用 CSS/JS 進行控制。

2)與分辨率無關,在任何分辨率的設備上都能清晰地展示。就不需要為高清屏準備二倍圖、三倍圖了。

3)容易編輯

4)高度可壓縮

來看下 SVG 格式與 JPG、GIF、PNG 圖片格式在使用上的區別:

image-20190728170717428

二、SVG 使用方法

使用 SVG 圖片有多種方式,每種方式都有自己的優缺點,選擇合適的方式就好。

1、在 Img 中引入

需要注意的是,使用這種方法在交互性上有很多限制,如不能使用 JS 來控制,不支持 CSS3 動畫。

2、通過 CSS 中 Background-image 引入

使用背景圖片方法需要注意的一點是,最好不要使用 base64 編碼來格式化 SVG 圖片,因為它在加載完前會阻塞其它資源的下載。使用這種方法在交互性上也有很多限制,如不能使用 JS 來控制,不支持 CSS3 動畫。

3、通過 Iframe 引入

不確定這是不是還是一種好的使用方法。

4、通過 Embed 引入

大多數瀏覽器都支持,但最好還是不要使用這種方法。

5、通過 Object 引入

如果你想使用 JS 來進行交互控制,<object> 是 SVG 使用方法中很好的一個選擇。 只需要把它放到 HTML 中就可以了。

6、將 SVG 元素直接加入到 HTML 中

把 SVG 直接插入到 HTML 中,可以節省 HTTP 請求,而且很方便使用 JS 來控制。但是這樣,SVG 資源就不能被瀏覽器緩存。同時使用 JS 來操控 SVG 會發生重繪行為。

這幾種使用方式的特點:

image-20190728170355429

三、在 React + Webpack 項目中如何引入 SVG?

在 webpack 中有各種 loader 可以加載 SVG:

1、url-loader

官方文檔:https://webpack.docschina.org/loaders/url-loader/

可以把 svg 當作普通 jpg、png 圖片來使用。

安裝:

webpack 配置:

在 React 組件中的引入方式:

經過 url-loader 處理后,test.svg 文件被處理為 "data:image/svg+xml;base64,PHN2ZyBpZ....." 這樣的 base64 編碼。

我們用 webpack-bundle-analyzer 插件測試看看 svg 文件被打包后的大?。?/p>

image-20190727213907016

此外 file-loader 也可以。

這種方式的優點: SVG 資源可被緩存,SVG 資源可單獨加載。

缺點:加載多個 SVG 文件時,會產生多個 http 請求,影響頁面加載性能。

2、svg-react-loader

安裝:

webpack 配置:

在 React 組件中的引入方式:

svg-react-loader 會將 svg 文件處理成 React 組件,最后會以 svg 標簽的形式渲染到 html 中。從最后渲染到 html 中的代碼來看,svg-react-loader 是有對 svg 原文件進行優化的。從打包后的文件大小可以看出來文件有被壓縮:

image-20190727214315507

這種方式的缺點:SVG 資源不可被緩存。且會將 svg 資源的處理邏輯與頁面的交互邏輯一起打包。

最好的方式是:SVG 資源與 JS 資源分離,圖片的加載不影響頁面的主要執行邏輯。并且所有的 SVG 資源希望能一次 HTTP 請求就能搞定。

3、svg-inline-loader

官方文檔:https://webpack.js.org/loaders/svg-inline-loader/

svg-inline-loader 會根據配置項去除 SVG 中冗余的代碼或者不必要的代碼,以減少 SVG 的文件大小。

安裝:

webpack 配置:

在 React 組件中的引入方式:

經過 svg-inline-loader 處理后 svg 文件被處理為這樣的字符串:

看下打包大小,相對比,這個體積優化的效果還不錯。

image-20190727220013803

此外還有 raw-loader 等都可以處理 SVG 文件。

四、SVG 優化

1. SVG 文件壓縮

一般設計師會使用 Adobe suite 或者 Sketch 等工具導出 SVG 文件,但這樣的 SVG 一般是有屬性冗余的,所以需要對 SVG 進行一定的壓縮。

手動壓縮:當然,也不需要手動壓縮,但是可以看看哪些屬性是有冗余的。

工具壓縮:推薦使用 SVGO。

webpack 項目中引入 SVGO:

安裝:

webpack 配置:

在單獨使用 url-loader 時,文件 test.svg 打包后的大小是:17.82 KB。在使用 svgo-loader 后,我們看下打包大小,確實是有很大幅度的壓縮。

image-20190727222022385

2. SVG 雪碧圖

當項目需要加載多個 SVG 文件時,上述加載方式就需要優化了。我們考慮以下幾種情況:

1)使用 url-loader 加載多個 svg 文件

image-20190727230155985

這種方式會產生多次 http 請求,而瀏覽器對并發請求數目是有限制的,請求太多會影響頁面加載性能。這種情況就需要引入雪碧圖,將多個 svg 文件合成一個 svg 文件。

2)使用 svg-react-loader ,當一個組件需要加載多個 svg 文件時,所有的 svg 文件都會被打包到 index.js 文件中。如果 svg 文件過多,就會增大 index.js 文件體積。而 SVG 作為圖片資源,最好是作為一個單獨文件異步加載,與頁面主要執行邏輯分離。當然這里也同樣需要引入雪碧圖。

第一種方法

第一種方法是把所有的圖標通過<symbol> 元素定義在 SVG 代碼中,嵌入在<symbol> 元素中的圖標是不會被直接顯示的。通過使用<use> 元素的 xlink:href="#id" 來引用單個圖標。

也就是說合成后的大 SVG 會是這樣:

在需要引入單個圖標的時候:

這里我們使用 svg-sprite-loader 來自動生成 svg 雪碧圖。

安裝:

loader 配置:

react 組件中引入:

這樣配置打包后,body 下會自動注入一個大的 SVG 元素,達到了雪碧圖的效果??墒沁@樣還是有兩個缺點:1)當需要使用這些 svg 的時候,需要在組件中單獨 import。2)這個大的 SVG 資源并沒有與 JS 資源分離。

image-20190728141342715

image-20190728142106996

為了解決第一個缺點:在組件加載前,增加自動 import 所有 svg 的功能:

現在可以自動導入了,不用到每個組件中去單獨 import 了??墒沁€需要解決第二個問題:SVG 資源與 JS 資源分離。

從 svg-sprite-loader 文檔中看到可以利用 spriteloaderplugin 插件將所有 SVG 文件打包輸出為一個大的 SVG:

這里的 loader 配置:

插件配置:

這種方式會在打包目錄下生成 sprite.svg 文件,我們可以通過 ajax 請求的方式獲取到該 svg 資源,然后將其注入到 html 中去,這樣就將 svg 資源與 js 資源分離了。

這樣的方式是我們自己手動去請求的,思考下能否使用 webpack 配置或者一些插件就能達到 svg 與 js 資源分離的目的呢。于是想到了 webpack 的 SplitChunksPlugin 插件提供的抽取公共代碼的能力。

于是嘗試把 import 所有 svg 的邏輯抽離出來成為一個單獨的 js 文件。配置好 SplitChunks 后,webpack 就會把這部分邏輯抽離出來,單獨打包成一個 js 文件。這樣就實現了 svg 與 js 資源分離了。

image-20190731212610492

webpack 配置:

第二種方法

第二種方法是使用 SVG 的 viewbox 屬性來指定顯示 SVG 畫布的區域,跟 background-position 原理差不多。待探索~

參考:

https://svgontheweb.com/

https://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial

https://www.sumydesigns.com/difference-jpg-gif-png-svg/

https://community.wia.io/d/6-generating-an-svg-sprite-sheet-with-webpack

原創文章轉載請注明:

轉載自AlloyTeam:http://www.ecomenagepro.com/2019/07/13782/

發表評論