這多是個別人寫過不少次的話題,但貌似因爲兼容性的緣由?圖標的顯示仍是用着 Iconfont
或者 CSS Sprite
的形式?
但願經過本身新瓶裝舊酒的方式能從新引導一下問題。javascript
比方說如今要作下圖這樣的視覺效果:css
分析:可能須要三張圖片html
如今對比一下背景圖使用圖片與使用 SVG 格式的體積大小(作圖的時候拿錯顏色了,其餘都同樣,能說明道理就行,見諒見諒)vue
能夠看出,在肉眼感受差別不大的狀況下,WebP
格式體積最小,其次是 SVG
,而 PNG
的體積過大。 java
這個 SVG
是在 Sketch
設計稿中導出來的,源碼包含了不少冗餘無效的代碼,其實是能夠優化的,以下。git
內部源碼github
優化後web
優化後大約能夠減去 1K
個字符。固然這個須要內聯使用(Inline SVG)瀏覽器
使用 CSS Sprite
的方式能夠減小 HTTP
請求,貌似還能夠減小整體圖片體積。
這裏用前景圖來對比一下,實際上背景圖和前景圖均可以合成一張 sprite
。性能優化
能夠看出,CSS Sprite
的體積比 Inline SVG + CSS
的方式大不少。
綠色部分表示 SVG
比 Image
略勝一籌的地方,黃色部分表示有所欠缺的地方,灰綠色表示差很少。
一、現在已接近 2019
年了,對於 IE9 (2011年)
這種古老的瀏覽器都支持 SVG
,因此再過多強調更低的兼容性也沒有什麼意思。
二、Inline SVG
在瀏覽器應該是被渲染成 DOM
節點,因此關於 DOM
節點的性能優化都有必要注意;一個 SVG
圖像可能就會有不少路徑,即 DOM
節點,太多的 DOM
節點必然會影響瀏覽器的渲染性能及內存佔用,而純位圖的渲染方式應該是沒有這方面的顧慮。(DOM
數量影響參考:Google WEB 開發者文檔)
除開復雜圖像,選擇 Inline SVG
或者 <img/>
標籤的方式引入 SVG
,會比使用 獨立圖像
或 組合圖像 (CSS sprite)
的方式更好。
首先看下Iconfont
與SVG
圖標的使用方式,來源 阿里 Iconfont 平臺
很明顯 SVG Sprite
使用起來沒有 Iconfont
方便,須要寫 3
行代碼, 然後者只須要寫 1
行。
固然上面的不是重點,重點是下面的換色與多色支持
一、Iconfont
經過 CSS color
能夠輕鬆更換圖標顏色。
二、而 SVG Sprite
比較麻煩,SVG Sprite
的代碼原理以下。
// 定義 symbol <svg> <symbol id="icon-arrow-left" viewBox="0 0 1024 1024"> <path d="M694 ... 44.576-45.952"></path> </symbol> <symbol id="icon-arrow-right" viewBox="0 0 1024 1024"> <path d="M693 ... 0-0.48-46.4"></path> </symbol> </svg> // 使用 <svg><use xlink:href="#icon-arrow-left"/></svg> <svg><use xlink:href="#icon-arrow-right"/></svg>
渲染出來的 DOM
結構是這樣的:
渲染在了 Shadow DOM
中(關於 Shadow DOM
的知識能夠閱讀下這篇文章或這篇),
這樣的 DOM
元素樣式就具備了做用域,外面的 CSS
對 shadow-root
內的元素不會生效,
若是想要更換元素的顏色,須要使用 /deep/
來穿透添加樣式,以下。
svg /deep/ path { fill: red; }
固然,實際上在只須要在父級元素上添加 fill: red
這樣的 CSS
也能起到一樣的效果,裏面的元素會繼承父級的樣式。
PS:/deep/
是shadow DOM v0
的寫法,v1
已經把這樣的寫法拋棄了,實際上支持v1
的shadow DOM
, 父級的樣式能夠直接做用在shadow-root
裏面的元素。
一、Iconfont
是不支持多色圖標的。
二、而 SVG Sprite
能夠利用 CSS
變量或 shadow DOM
的方式支持多色圖標,shadow DOM
的方式上面已經說明,下面借用他人的文章解釋 CSS
變量實現多色,以下。
不過使用 CSS
變量或 shadow DOM
的方式兼容性都很差,
CSS
變量:Edge15+shadow DOM
:更差。兼容性列表 三、Inline SVG
能夠良好地支持多色及多色變化。
Iconfont
與 SVG Sprite
不支持漸變色。Inline SVG
支持漸變色,而且兼容性良好。
使用 Iconfont
,由於字體文件是異步加載的,因此在字體文件尚未加載完畢以前,圖標位會留空,加載完畢後纔會顯示出來,這個過程就會出現向下圖(來自 GitHub blog)這樣的抖動,而 SVG Sprite
或 Inline SVG
內聯加載則不會出現這樣的抖動。
固然,Iconfont
也能夠內聯加載,不過須要轉換成 base64
一樣式表一塊兒加載,轉換後的文件體積則會變爲原來的 1.3
倍左右
這是由 base64
編碼決定的(編碼知識連接)。
字體轉換成
base64
的一個在線工具:
https://transfonter.org/
這個是 SVG
對比於 Iconfont
的一個不足之處,以下圖。
Inline SVG
與SVG Sprite
體積差很少。
三者的開發成本都差很少,不過 SVG
的兩種方式都須要前期作些配置,後期開發就會順手不少(單頁應用)。
以 vue + vue cli
爲例說明 Inline SVG
便捷使用。
Webpack loader
:{ // 排除須要轉換成 Inline SVG 的目錄 exclude: [resolve('src/svgicons')], test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 1, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { // 指定特定的目錄用於 Inline SVG include: [resolve('src/svgicons')], test: /\.svg$/, use: [ // 讀取 SVG 源代碼 { loader: 'raw-loader' }, // 精簡優化 SVG 源代碼 { loader: 'svgo-loader', options: { plugins: [ { removeTitle: true }, { removeViewBox: false }, { removeDimensions: true }, // ...其餘參數 ] } } ] }
SvgIcon.vue
組件:<template> <div class="svg-icon"> <div class="svg-icon-wrapper" v-html="icon"></div> </div> </template> <script> export default { name: 'SvgIcon', props: { name: { type: String, required: true, }, }, data () { return { icon: this.getIcon(), } }, watch: { name () { this.icon = this.getIcon() }, }, methods: { getIcon () { return require(`@/svgicons/${this.name}.svg`) }, }, } </script> <style lang="stylus" scoped> .svg-icon { overflow hidden display inline-block width 1em height 1em &-wrapper { display flex align-items center >>> svg { width 100% height 100% fill currentColor *[fill='none'] { fill none } *[stroke='none'] { stroke none } } } } </style> <style lang="stylus"> .svg-icon-hover { &:hover { svg { *[fill] { fill currentColor } *[stroke] { stroke currentColor } } } } </style>
<SvgIcon name="arrow-right" /> 或者 <a class="svg-icon-hover" href="#"> <SvgIcon name="arrow-right" /> </a>
應該是 Inline SVG vs SVG Sprite vs Iconfont
的結論,以下圖。
選擇 Inline SVG
或許是一個不錯地選擇去替代 Iconfont
的使用方式。
Iconfont
轉成了 Inline SVG
, 這一篇文章是他們的描述:歡迎各抒己見談論一下對 SVG
和 Iconfont
的見解,優缺點,歡迎留言。
而後,本文同步發表於【凹凸實驗室博客】或微信公衆號,歡迎關注咱們,麼麼噠。