1. 程式人生 > >SVG Sprite技術介紹

SVG Sprite技術介紹

問題 tor 位置 mage display 不定 頭部 posit 知識

未來必熱:SVG Sprite技術介紹技術分享圖片

這篇文章發布於 2014年07月10日,星期四,18:03,歸類於 SVG相關。 閱讀 100049 次, 今日 15 次

一、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開發中,為何?

兩點:

  1. 可重復調用;
  2. 跨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對應的就是idshape的元素。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實際應用的阻礙

兩大問題:

  1. SVG圖標從何而來?
  2. 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上,有個名為svgstoregrunt插件,地址戳這裏。如果您還不了解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文件夾下。

我們cdgrunt-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!

一步一步跟我來:

  1. 打開軟件,新建一個文件,然後另存為SVG格式;
  2. 從標尺中拉出一些參考線,搞些正方形格子,我自己用的尺寸是160*160, 矢量無尺寸,你隨意;
  3. 把下載的SVG圖形拖到這些格子中,縮放到合適大小。我是鋪滿的,這樣由於對比明顯,各個圖標尺寸就都是一致的,CSS控制方便;
    技術分享圖片
  4. 這一步很關鍵。打開Symbols面板,在Window菜單欄中,或Shift+Ctrl+F11啟用。然後,拖動格子中的SVG圖形到這個面板中,就會觸發新建“元件”的行為,會打開類似下面的面板:
    技術分享圖片

    其中,name就是SVG中對應的symbol元素的id,因此,最好使用英文,最好易識別。下面的type你隨意,這個只要在SVG導入到Flash中使用時候才有用的,這裏,我們不和Flash打交道。然後,OK, 這個圖標就“元件”化了,按照同樣的步驟,讓3個圖標都變成元件(以後可重復使用),Symbols面板會類似下面這樣:
    技術分享圖片

  5. 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, spspecial的縮寫,專門放工具用的。

使用很簡單:

  1. 把illustrator生成SVG所有代碼拷貝到第一個框框裏;
  2. 點擊“轉換萌萌噠”按鈕,適用於SVG Sprite技術的新代碼就出來了(左下的框框);同時,右側顯示了如何使用該SVG Sprite在web中真實實踐;
  3. 左下角還有個紅色的“導出該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.

  1. 進入 http://icomoon.io/app/
  2. 點擊”import icons”按鈕:
    技術分享圖片
  3. 選擇需要的圖標:
    技術分享圖片
  4. 點擊頁面下面固定的SVG按鈕:
    技術分享圖片
  5. 點擊打開的彈框的download按鈕即可:
    技術分享圖片
  6. 下載的源文件中,有兩個文件夾,其中sprites文件夾中,有合並好的SVG, png圖標以及對應的demo, 這個絕不會迷路的,就不截圖展示了。

嘛,就此看來,這裏才是老少皆宜,SVG Sprites整合最容易的地方。不過:

  1. 元素還是使用的g整合,svgstore以前也是,後來改成了symbol, 這裏也可能在一段時日後也會修改,但並不確定;
  2. 名為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新舞臺!

感謝閱讀,歡迎交流,踴躍糾錯,多多贊助!技術分享圖片

(本篇完)

SVG Sprite技術介紹