SVG Sprite技術介紹
未來必熱:SVG Sprite技術介紹
這篇文章發布於 2014年07月10日,星期四,18:03,歸類於 SVG相關。 閱讀 100049 次, 今日 15 次by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=4264
一、Sprite技術
這裏所說的Sprite技術,沒錯,類似於CSS中的Sprite技術。圖標圖形整合在一起,實際呈現的時候準確顯示特定圖標。
另,本文圖片甚多,爪機黨繼續瀏覽需慎重。
二、SVG Sprite與symbol元素
目前,SVG Sprite最佳實踐是使用symbol
symbol
元素是什麽呢?單純翻譯的話,是“符號”的意思。然,這個釋義並不符合這裏的場景。不知大家有沒有用過Flash,symbol
實際上就類似於Flash中的“影片剪輯”、或者“元件”。
因此,我個人覺得,symbol
應該解釋為“元件”最為恰當!
那,symbol
和SVG Sprite又有什麽關系呢?
我們可以把SVG元素看成一個舞臺,而symbol
則是舞臺上一個一個組裝好的元件,這這些一個一個的元件就是我們即將使用的一個一個SVG圖標。
於是,對於一個集合了三個SVG圖標的SVG元素的代碼結構會是這樣:
<svg> <symbol> <!-- 第1個圖標路徑形狀之類代碼 --> </symbol> <symbol> <!-- 第2個圖標路徑形狀之類代碼 --> </symbol> <symbol> <!-- 第3個圖標路徑形狀之類代碼 --> </symbol> </svg>
每一個symbol
就是一個圖標元件,但是,只有上面的代碼,是無法呈現類似下面的效果的:
為何?
因為,舞臺上只是放置了圖標,如果你不使用(use),是看不見的。就好比你女朋友買了幾箱的衣服放家裏,如果不穿出去,誰知道她這麽土豪呢?
因此,還差一個“使用”,也就是SVG中的<use>
元素。
三、SVG中的use元素
use元素是SVG中非常強大,非常重要的一個元素,尤其在Web開發中,為何?
兩點:
- 可重復調用;
- 跨SVG調用;
1. 可重復調用
你好不容易,用了幾十個坐標值,好不容易繪制了一個圖形,如果你想再弄一個同樣造型,但位置不同的圖形出來,你會怎麽辦?——再復制一遍代碼?別說笑了,(如果真那樣)SVG文件的尺寸趕得上二師兄的腰圍了。
使用<use>
元素就可以,看下面的板栗:
<svg> <defs> <g id="shape"> <rect x="0" y="0" width="50" height="50" /> <circle cx="0" cy="0" r="50" /> </g> </defs> <use xlink:href="#shape" x="50" y="50" /> <use xlink:href="#shape" x="200" y="50" /> </svg>
結果是(IE9+瀏覽器可見):
首先,註意到沒有,use
元素是通過xlink:href
屬性,尋找要使用的元素的。#shape
對應的就是id
為shape
的元素。use
元素可以有自己的坐標,以及支持transform
變換,甚至可以use其他use
元素。
這裏,兩個use
元素使用的是同一個g
元素(組合),從而實現了圖形的重復調用功能。
2. 跨SVG調用
SVG中的use
元素可以調用其他SVG文件的元素,只要在一個文檔中。
緊接著上面的板栗:
<svg width="500" height="110"><use xlink:href="#shape" x="50" y="50" /></svg>
結果仍是那個圖形:
而這個跨SVG調用就是“SVG Sprite技術”的核心所在。
試想下,我們只要在頁面某處載入一個充滿Sprite(symbol
)的SVG文件(或直接include
SVG代碼),於是,在頁面的任何角落,只要想使用這個圖標,只要簡單這一點代碼就可以了:
<svg class="size"><use xlink:href="#target" /></svg>
圖標尺寸CSS控制,裏面只有一個僅有xlink:href
屬性的use
元素,Done! 完成!
也即是說,在HTML層面,圖標使用的代碼成本,跟傳統的CSS Sprite或者流行的font-face
幾乎無異,代碼簡潔,而且很好維護。所有的SVG圖標都在一個SVG源上。retina良好,尺寸可任意拉伸,且顏色可控,真乃Web圖標的未來之星。
吹的嘴巴都幹了,上個簡單的demo給大家瞅瞅, 我先去給水排水~~
您可以狠狠地點擊這裏:SVG Sprite使用示意demo
代碼如下截圖:
效果為:
總結下就是:symbol + use => SVG Sprite
諸位會不會覺得本文的內容快要結束了呢?
嘻嘻嘻嘻,頂多才1/3,下面的才是重點,打起精神,走起~~
四、SVG Sprite實際應用的阻礙
兩大問題:
- SVG圖標從何而來?
- SVG圖標如何變成symbol並整合在一起?
第1個問題,SVG圖標從何而來?
“遠在天邊近在眼前”,CSS3 font-face
的逐漸升溫,讓很多font-face
工具誕生了。例如以前我介紹過的國外的icomoon.io,或者國內阿裏系的iconfont.cn, 或者bootsrap 3粉們的font-awesome
這些圖標實際上都是使用SVG作為媒介的,所以,根本就不要擔心“SVG圖標從何而來”,這圖標多的就像牛魔王身上的虱子——一抖一大把啊!
OK,如何獲得呢?直接下載。拿iconfont.cn示意,點擊某一圖標的下載按鈕:
點擊下載SVG:
於是,我們就得到了SVG圖標啦!如果你還需要其他圖標,也按照這個步驟一個一個下載下來,很簡單吧~ 然後把它們放在一個文件夾中,以備後用。
下面最關鍵的是第2個問題,如何合並這些SVG到一個SVG上?同時滿足使用的是symbol
標簽,並可以使用裸露的use
元素(除了xlink:href
沒有其他屬性)調用呢?
很長很funny, 要專門獨立兩段,
五、關於合並:偏開發的前端看這裏
這裏的方法適用於偏開發的前端,一些對指令無感的妹子們,可以看下面偏設計的方法。
Github上,有個名為svgstore
的grunt
插件,地址戳這裏。如果您還不了解grunt
, 可以看看這兩篇我覺得不錯的文章:“使用GruntJS構建Web程序 (1)”和“使用GruntJS構建Web程序 (2)”.
grunt
改裝的裝好後,執行下面的指令,
npm install grunt-svgstore --save-dev
燒個香保佑安裝成功,然後你就會看到在node_modules
文件夾中一個名為grunt-svgstore
的子文件夾(如下):
這個名為grunt-svgstore
的文件夾中有個名為Gruntfile.js
的文件,據我個人理解,這個JS是所有grunt
插件要使用的配置文件。
我在裏面做了一件事情,加了這麽一行代碼:
為什麽要加這麽行代碼呢?因為grunt-svgstore項目README.md讓加的,所以我就加了 。
你會看到
svgstore: { }
中有一大堆的配置什麽的,這些都是用來獨立測試各個API的(options
對象中各個鍵就是API名稱),讓你知道此插件各個API都是幹嘛用的,具體釋義參見該Github項目。忍不住提一下,如果你希望SVG圖標顏色可以在CSS中通過fill
控制,cleanup
設置為true
.
OK, 準備工作完畢,下面來實踐下。我把從iconfont.cn上下載下來的3個SVG都放在了一個名為mytest
的文件夾下,我希望這個文件夾下的SVG都整合在一起,並可以方便調用,怎麽辦?
在svgstore: {}
內部搞個自定義的配置,見下圖:
意思是:mytest
文件夾下的所有SVG合並成一個名為mytest.svg
的大SVG文件,並放在tmp
文件夾下。
我們cd
到grunt-svgstore
目錄,然後在命令行工具中輸入:
grunt
然後走起,再燒第2根香,保佑一切正常……
然後,就可以在tmp文件夾下看到我們的小結晶——mytest.svg
,以及如何使用示意的HTML demo頁面。
此demo頁面源代碼如下:
<svg xmlns="http://www.w3.org/2000/svg" style="width:0;height:0;visibility:hidden;"><symbol viewBox="0 0 1024 1024" id="iconfont-baobei"><title>iconfont-baobei</title><path fill="#272636" d="M...z" transform="translate(0, 800) scale(1, -1)"/></symbol><symbol viewBox="0 0 1024 1024" id="iconfont-bianji"><title>iconfont-bianji</title><path fill="#272636" d="M...z" transform="translate(0, 800) scale(1, -1)"/></symbol><symbol viewBox="0 0 1024 1024" id="iconfont-shangchuan"><title>iconfont-shangchuan</title><path fill="#272636" d="M...z" transform="translate(0, 800) scale(1, -1)"/></symbol></svg> <svg> <use xlink:href="#iconfont-baobei"></use> </svg> <svg> <use xlink:href="#iconfont-bianji"></use> </svg> <svg> <use xlink:href="#iconfont-shangchuan"></use> </svg>
效果如下截圖:
Oh, no! 怎麽有殘缺,不完美,感覺不會再愛了!
淡定,小問題,貌似是這些SVG制作的時候,本身有些問題(為了font-face做的調整?),我們在illustrator中打開這些SVG, 一下子就可以看出癥結所在,例如,細細的鉛筆圖標:
鉛筆的兩個角在白色的舞臺之外了,正好跟上面截圖少掉的兩個角一致。要修復,超easy, 等比例縮放到白色舞臺內就OK了,ctrl+S保存,然後重新執行下grunt
命令就好了。
然後,瀏覽器刷新下剛剛的demo頁面,當當當當,撒花撒花~~
以上~
六、關於合並:偏設計的前端看這裏
註意:這裏的方法,就算是CSS完全不懂的設計師也可以輕松上手!
對於一些妹子,只會寫些頁面,對於開發、編程的感覺比減肥還難,顯然,上面的偏開發需編譯的工具插件對她們就很吃力。不急不急,這裏有面向設計師的方法。
你需要一個犀利的軟件,矢量之王,illustrator!
一步一步跟我來:
- 打開軟件,新建一個文件,然後另存為SVG格式;
- 從標尺中拉出一些參考線,搞些正方形格子,我自己用的尺寸是
160*160
, 矢量無尺寸,你隨意; - 把下載的SVG圖形拖到這些格子中,縮放到合適大小。我是鋪滿的,這樣由於對比明顯,各個圖標尺寸就都是一致的,CSS控制方便;
- 這一步很關鍵。打開Symbols面板,在Window菜單欄中,或Shift+Ctrl+F11啟用。然後,拖動格子中的SVG圖形到這個面板中,就會觸發新建“元件”的行為,會打開類似下面的面板:
其中,
name
就是SVG中對應的symbol
元素的id
,因此,最好使用英文,最好易識別。下面的type
你隨意,這個只要在SVG導入到Flash中使用時候才有用的,這裏,我們不和Flash打交道。然後,OK, 這個圖標就“元件”化了,按照同樣的步驟,讓3個圖標都變成元件(以後可重復使用),Symbols面板會類似下面這樣: - Ctrl+S保存,合並好的SVG即出爐。我們直接在瀏覽器中打開此SVG,效果不錯哦~
是不是就這麽結束了,太天真了。人生不如意事十之八九。我們瞅一瞅SVG的源代碼,會發現,use
元素居然跟小龍女一樣,不幹凈純潔啦——上面一大推亂七八糟的屬性!
難道我們要在網頁中使用如此臃腫的use
元素嗎?
我以小新的明義告訴你,絕對不會!
因為我昨晚在家折騰出了個工具,可以將illustrator生成SVG轉換成web可用SVG Sprite.
您可以狠狠地點擊這裏:illustrator生成SVG轉換成web可用SVG Sprite工具demo
上工具完整地址是:http://www.zhangxinxu.com/sp/svg.html 很好記憶,我站點域名+sp+svg.html
, sp
是special
的縮寫,專門放工具用的。
使用很簡單:
- 把illustrator生成SVG所有代碼拷貝到第一個框框裏;
- 點擊“轉換萌萌噠”按鈕,適用於SVG Sprite技術的新代碼就出來了(左下的框框);同時,右側顯示了如何使用該SVG Sprite在web中真實實踐;
- 左下角還有個紅色的“導出該SVG”,就是字面意思,可以自定義名稱,也可使用隨機名稱,為空即可;
一開始的SVG Sprite使用示意demo就是使用這個工具生成的哦~ 見下縮略圖:
註意:此工具值適用於illustrator生成的SVG, 水平有限,其他SVG轉換十有八九會跛掉。沒怎麽測試,如果發現此工具轉換出了問題,歡迎提醒,定會及時修復。另外,生成的SVG文件會不定期清理,請勿外鏈。
我想想,還有沒有什麽問題……哦,為什麽說此方法與CSS Sprite還要簡單。
因為,CSS Sprite還需要在CSS中使用background-position
一個一個地定位,哦,天哪~ 如果沒有工具的話,就純粹搬磚的苦力活啊~
但是,這裏的SVG Sprite的定位,你只要在illustrator中把位置放好,illustrator這個軟件就自動幫你定位好了。你只要在我的工具中轉換下,生成下,然後在需要使用的地方使用:
<svg><use xlink:href="#target" /></svg>
就好了,用到CSS了嗎?幾乎沒有,除了對SVG做尺寸限制以及改變圖標的顏色。OK,這點程度的東西,小白設計師也可以輕松上手。
從這一點來看,SVG又一次成為了明日之星!設計師只要在illustrator中做好圖就可以了,完全沒有從前那種幫重構切圖的苦逼經歷了,是不是要啤酒炸雞慶祝下!
補充於2014年7月14日
IcoMoon目前可以直接轉換成SVG Sprite.
- 進入 http://icomoon.io/app/
- 點擊”import icons”按鈕:
- 選擇需要的圖標:
- 點擊頁面下面固定的SVG按鈕:
- 點擊打開的彈框的download按鈕即可:
- 下載的源文件中,有兩個文件夾,其中sprites文件夾中,有合並好的SVG, png圖標以及對應的demo, 這個絕不會迷路的,就不截圖展示了。
嘛,就此看來,這裏才是老少皆宜,SVG Sprites整合最容易的地方。不過:
- 元素還是使用的
g
整合,svgstore以前也是,後來改成了symbol
, 這裏也可能在一段時日後也會修改,但並不確定; - 名為
sprites.html
的demo頁面的SVG還使用了viewbox
做限制,我測試了,刪掉似乎也沒問題;
補充於2014年12月21日
註意註意:SVG Sprite技術是支持外鏈SVG文件的,例如:
<svg viewBox="0 0 100 100"> <use xlink:href="defs.svg#icon-1"></use> </svg>
所以,很多不喜歡內聯SVG的小夥伴大可放心使用該技術。但是,美中不足的是,目前,所有的IE瀏覽器(包括IE11)還不支持獲得外鏈SVG文件某個元件。Chrome/FireFox/Safari/Opera等瀏覽器都是OK的。
補充於2015年3月18日
SVG Sprite技術是支持直接Ajax請求SVG文件字符串的。因此,對於不支持外鏈的IE9+瀏覽器,可以直接:
var ajax = new XMLHttpRequest(); ajax.open("GET", "../201407/mytest.svg", true); ajax.onload = function(e) { document.body.insertAdjacentHTML("afterBegin", ‘<div style="display:none;">‘ + ajax.responseText + ‘</div>‘); } ajax.send();
您可以狠狠地點擊這裏:Ajax請求SVG文件實現Sprites效果Demo
例如,IE9瀏覽器下:
因此,大家大可不必擔心SVG資源管理之類的問題。IE9等瀏覽器,一次Ajax成功後,可以直接本地存儲,想想就很棒!
補充於2016年10月27日
部分華為Android手機,這種後置的ajax請求SVG寫入方式無法呈現小圖標,如果在頁面頭部一開始就有SVG文件代碼資源,則沒有此問題,圖標不會顯示不出來。
要修復此方法,可以把SVG資源作為一個JS資源載入,例如,命名一個名叫sprite.js
,裏面代碼大致如下:
var SVG = ‘<svg xmlns="http://www.w3.org/2000/svg"><symbol id="icon-arrow-l" viewBox="0 0 8 16"><path d="M.146 7.646a.5.5 0 0 0 0 .708l7 7a.5.5 0 0 0 .708-.708l-7-7v.708l7-7a.5.5 0 0 0-.708-.708l-7 7z"/></symbol><symbol id="icon-arrow-r" viewBox="0 0 7 12"><path d="M6.146 6.354v-.708l-5.5 5.5a.5.5 0 0 0 .708.708l5.5-5.5a.5.5 0 0 0 0-.708l-5.5-5.5a.5.5 0 1 0-.708.708l5.5 5.5z"/></symbol><symbol ....</symbol></svg>‘; document.body.insertAdjacentHTML("afterBegin", ‘‘);
然後在頁面body
標簽的下面,直接:
<script src="sprite.js"></script>
類似下圖:
七、唯一的制約——兼容性
SVG圖標必定是未來的趨勢。為何現在國內依然不溫不火,不對,應該是還沒有開始有溫度。我覺得除了技術學習滯後性,瀏覽器兼容性是最關鍵的制約,畢竟IE8目前依然是大頭(33.23%, 剛在百度流量研究院看到的數據)。
如何破?按照我的心情,鳥它個毛線,我就手機上用用,不也挺好。靜下來想想,不能意氣用事,提一下IE7/IE8瀏覽器的處理方法吧~
有些標簽,瀏覽器識別,會忽略裏面一些東西。例如SVG的desc
元素,裏面的內容一向不顯示的。於是,對於IE7/IE8, 我們可以把對應圖標的png
圖片放在其中,然後IE9+等支持SVG的瀏覽器就會忽略之,而IE7/IE8這些不識泰山的元素就會顯示圖片。拿禮物這個SVG舉例:
<svg class="webicon"> <desc><img src="iconfont-baobei.png" width="16" height="16"></desc> <use xlink:href="#liwu"/> </svg>兌換禮物
於是,在IE8下,就會是這樣:
其他靠譜瀏覽器依然是這樣:
於是,完美兼容了。只是活脫脫多了個標簽,略敗興。當然,你也可以針對IE7/IE8使用CSS Sprite技術,原理類似,只是img
標簽換成其他i
之類標簽顯示背景圖,至少HTML這塊會幹凈很多。
八、結束語
今年4月份的時候剛介紹過“CSS3圖標圖形生成技術”,如果說“font-face
圖標生成技術”是熱門的話,那“CSS3圖標生成技術”則屬於偏門,受設計制約很大,而本文介紹的“SVG Sprite圖標生成”則代表了未來。
font-face
在部分win系統下,字體較小的時候,鋸齒問題很討厭,苛刻的設計師無法忍受,甚至出現了響應式font-face
這樣的名堂,但是,據我觀察,純正的SVG圖標是沒有這個問題的,而且,SVG圖標具備font-face
幾乎所有的優點,尺寸CSS可隨意定制,顏色CSS可隨意定制;且沒有font-face
異步加載延時渲染問題;同時沒有某些瀏覽器下font-face
跨域問題;更關鍵的是,SVG圖標支持漸變,甚至彩色圖標的。而font-face
實現彩色圖標,要一個一個拼起來,你以為貼馬賽克啊!而且,SVG中每個path
元素等可以獨立控制,帥氣的圖標變換動畫等的就是你來實現(add on 2014/7/18 這個頁面N多SVG圖標動畫)!
因此,各方面看,SVG完勝font-face
,
目前唯一的問題就是兼容成本(當然,業界還是有很多成熟的優雅降級技術,可參見我之前的文章“一些SVG向下兼容優雅降級技術”)。但是,隨著瀏覽器的發展,SVG一定會迎來自己Web新舞臺!
感謝閱讀,歡迎交流,踴躍糾錯,多多贊助!
本文為原創文章,會經常更新知識點以及修正一些錯誤,因此轉載請保留原出處,方便溯源,避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本文地址:http://www.zhangxinxu.com/wordpress/?p=4264
(本篇完)
SVG Sprite技術介紹