一、之前SVG背景圖的做法
在寫這篇文章之前,對於SVG圖標或圖形,如果作為CSS背景使用,只要尺寸不超過2K,很多時候我都是直接內聯在CSS代碼中的,采用的形式是base64格式。
相關CSS代碼如下:
.icon-arrow-down {
width: 20px; height: 20px; background: url(data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHZpZXdCb3g9IjAgMCAyMDAgMjAwIj48cGF0aCBmaWxsPSIjMjQ4NmZmIiBkPSJNMTQ1LjY1OSw2OC45NDljLTUuMTAxLTUuMjA4LTEzLjM3Mi01LjIwOC0xOC40NzMsMEw5OS40NzksOTcuMjMzIEw3MS43NzIsNjguOTQ5Yy01LjEtNS4yMDgtMTMuMzcxLTUuMjA4LTE4LjQ3MywwYy01LjA5OSw1LjIwOC01LjA5OSwxMy42NDgsMCwxOC44NTdsNDYuMTgsNDcuMTRsNDYuMTgxLTQ3LjE0IEMxNTAuNzU5LDgyLjU5OCwxNTAuNzU5LDc0LjE1NywxNDUuNjU5LDY4Ljk0OXoiLz48L3N2Zz4NCg==) no-repeat center/100%; }
矢量,少了個文件請求,渲染幾乎無延時,自認為性價比不錯。
然而,今天我發現,對於SVG圖形,使用Base64格式進行內聯,並不是最佳的做法,還有更好的實現方式,就是直接使用SVG XML格式代碼,無需進行base64轉換。
二、SVG直接內聯
方法就是把SVG代碼直接內聯在CSS的url()方法中,語法就是data:image/svg+xml;utf8,加上完整的SVG代碼即可!例如比較常用的background-image的url()方法,代碼如下:
.icon-arrow-down {
width: 20px; height: 20px; background: url('data:image/svg+xml;utf8,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><path fill="#00A5E0" d="M145.659,68.949c-5.101-5.208-13.372-5.208-18.473,0L99.479,97.233 L71.772,68.949c-5.1-5.208-13.371-5.208-18.473,0c-5.099,5.208-5.099,13.648,0,18.857l46.18,47.14l46.181-47.14 C150.759,82.598,150.759,74.157,145.659,68.949z"/></svg>') no-repeat center; background-size: 100%; }
使IE瀏覽器也支持的處理
首先,我們對所有SVG字符進行URL-encode肯定是OK的,例如執行:
encodeURIComponent('<svg version="1.1" ...</svg>')
得到如下CSS:
.icon-arrow-down {
width: 20px; height: 20px; background: url(data:image/svg+xml,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22200%22%20height%3D%22200%22%20viewBox%3D%220%200%20200%20200%22%3E%3Cpath%20fill%3D%22%2300A5E0%22%20d%3D%22M145.659%2C68.949c-5.101-5.208-13.372-5.208-18.473%2C0L99.479%2C97.233%20L71.772%2C68.949c-5.1-5.208-13.371-5.208-18.473%2C0c-5.099%2C5.208-5.099%2C13.648%2C0%2C18.857l46.18%2C47.14l46.181-47.14%20C150.759%2C82.598%2C150.759%2C74.157%2C145.659%2C68.949z%22%2F%3E%3C%2Fsvg%3E) no-repeat center; background-size: 100%; }
結果IE瀏覽器下SVG圖標出現了(包括IE9瀏覽器)
但是,完全URL-encode后也會帶來另外的問題,和轉義前原始SVG相比,可讀性差了很多,想改個顏色都找不到在哪里。那有沒有可以進一步提升的空間呢?
有!
部分URL encode IE瀏覽器也兼容
實際上,完全URL encode是沒有必要的,也就是,我們無需讓所有的字符都encode也能讓IE瀏覽器正確識別。根據前輩的實踐,只需要對下面這些字符轉義就能滿足絕大多數的場景,它們是:",%,#,{,},<,>。
其中,由於XML中屬性值雙引號單引號沒有區別,因此我們可以改成單引號',省去轉換還增加了可讀性,然后url()中使用雙引號"包起來。
於是,下面的CSS加內嵌SVG代碼就能在IE瀏覽器下正常工作:
.icon-arrow-down {
width: 20px; height: 20px; background: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cpath fill='%2300A5E0' d='M145.659,68.949c-5.101-5.208-13.372-5.208-18.473,0L99.479,97.233 L71.772,68.949c-5.1-5.208-13.371-5.208-18.473,0c-5.099,5.208-5.099,13.648,0,18.857l46.18,47.14l46.181-47.14 C150.759,82.598,150.759,74.157,145.659,68.949z'/%3E%3C/svg%3E") no-repeat center; background-size: 100%; }
結果IE9+瀏覽器下SVG背景也能正常顯示
可以看到,部分轉義后的SVG代碼既滿足的兼容性要求,同時可讀性也有了進一步的提高。
例如,我們想改變此SVG圖標的顏色,就簡單了,直接把fill='%2300A5E0'這里的00A5E0改成我們希望的十六進制顏色值即可。要是以前的Base64格式,改顏色是不可能的,需要該原始SVG並重新生成一下,特麻煩。
而且,直接原始SVG內嵌,即使有部分轉義,其字符大小也明顯比Base64格式要小。因此,理論上,CSS中內聯SVG背景圖,沒有使用Base64格式的理由。但,目前大規模使用還有一個阻礙,就是缺少轉換的工具,總不可能每次我們都手動修改需要轉義的字符吧。
不要擔心,工具是會有的,我這就給大家寫一個,自帶壓縮和轉義。
轉義的JS代碼其實很簡單,示意如下:
var encodeSvg = function (str) { return "data:image/svg+xml," + str.replace(/"/g,"'").replace(/%/g,"%25").replace(/#/g,"%23").replace(/{/g,"%7B").replace(/}/g,"%7D").replace(/</g,"%3C").replace(/>/g,"%3E"); }
