SVG便可縮放矢量圖形 (Scalable Vector Graphics)的簡稱, 是一種用來描述二維矢量圖形的XML標記語言. SVG圖形不依賴於分辨率, 所以圖形不會由於放大而顯示出明顯的鋸齒邊緣.javascript
當咱們須要使用多個icon的時候, 爲了節省請求和方便管理, 一般會把icon合併到一個文件中, 在使用時再經過必定的方法從icon集合文件中取出所需的圖形並顯示. 目前使用得最多的應該就是咱們所熟悉的CSS Sprite和Icon Font.css
CSS Sprite的原理是將多個icon按必定規律整理到一個圖片文件中, 使用時利用background-image
和background-position
將圖片中特定部分顯示出來. CSS Sprite技術已經被普遍應用了很長的一段時間, 目前有許多自動化生成Sprite圖片和CSS文件的工具, 例如(gulp.spritesmith)[github.com/twolfson/gu…].html
.icon1 {
background-image: url(/res/icon1.png)
}
.icon1-increase {
background-position: -10px -10px;
}複製代碼
<i class="icon1 icon1-increase"/>複製代碼
CSS Sprite技術成熟, 兼容性好, 可是缺點也比較明顯. 如在實際需求中, 對應形狀相同但顏色不一樣的icon, 就須要爲不一樣顏色的icon各保存一份; 有時候須要對已有icon放大顯示時, 發現鋸齒嚴重, 那麼又要再保存一份放大版的icon. 所以, Sprite文件會隨着時間越變越大, 同時內容愈來愈亂, 逐漸變得難以管理.java
Icon Font的基本原理是將Icon定義爲圖片字體, 在CSS中用@font-face
引入Icon Font自定義字體, 再利用font-family
和字符碼顯示出指定的圖標.git
@font-face {
font-family: 'iconfont';
src: url(/res/icon2.ttf) format('truetype');
}
.icon2 {
font-family: 'iconfont';
}複製代碼
<i class="icon2">!</i>複製代碼
因爲使用的是字體, 所以能夠經過color
, font-size
設置icon的樣式. Icon Font擁有比CSS Sprite圖片更小的文件體積, 維護也比圖片更方便, 可是icon font一般只能使用單一的顏色, 字體文件生成也比CSS Sprite更復雜.github
一般在使用SVG的時候, 咱們是直接寫到svg
標籤當中:express
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="100" viewBox="0 0 3 2">
<rect width="1" height="2" x="0" fill="#008d46" />
<rect width="1" height="2" x="1" fill="#ffffff" />
<rect width="1" height="2" x="2" fill="#d2232c" />
</svg>複製代碼
此時SVG圖形會直接在頁面當中顯示. SVG屬性中, 能夠利用(symbol
)[developer.mozilla.org/zh-CN/docs/…, 並利用(use
)[developer.mozilla.org/zh-CN/docs/…, 從而實現SVG Sprite的功能.gulp
SVG Sprite實例:瀏覽器
<svg style="height:0;width:0;display:none;" version="1.1" xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-italy" width="150" height="100" viewBox="0 0 3 2">
<rect width="1" height="2" x="0" fill="#008d46" />
<rect width="1" height="2" x="1" fill="#ffffff" />
<rect width="1" height="2" x="2" fill="#d2232c" />
</symbol>
<symbol id="icon-france" width="150" height="100" viewBox="0 0 3 2">
<rect width="1" height="2" x="0" fill="#002496" />
<rect width="1" height="2" x="1" fill="#ffffff" />
<rect width="1" height="2" x="2" fill="#ee2839" />
</symbol>
</svg>
<svg><use xlink:href="#icon-italy"/></svg>
<svg><use xlink:href="#icon-france"/></svg>複製代碼
這樣就實現了SVG Sprite.app
經過devtool能夠觀察到, use
標籤是利用shadow dom實現的.
它經過xlink:href
這個XML的attribute
引用指定的SVG symbol
, 在渲染時指定symbol
標籤中的內容就會被渲染顯示在頁面當中. 這意味着, 若是沒法直接對use
標籤中的shadow dom進行訪問和修改. 例如像use#rect
這樣的選擇器是沒法生效的, 所以不能經過通常的css選擇器對use
中圖形不一樣的部分進行控制.
更多的時候, 咱們一般都只須要改變圖標的大小和顏色, 在SVG Sprite當中, 實現起來並不複雜.
經過改變svg
容器的大小, 能夠輕鬆地對圖標大小進行控制.
.icon{
width: 120px;
height: 80px;
}
.icon.icon-small{
width: 60px;
height: 40px;
}複製代碼
<svg class="icon"><use xlink:href="#icon-italy"/></svg>
<svg class="icon icon-small"><use xlink:href="#icon-italy"/></svg>複製代碼
顏色因爲不能直接對use
的shadow root中的圖形標籤進行選擇, 所以在爲圖標定義顏色時須要利用fill: inherit
這個一屬性.
svg path{
fill: inherit;
}
.icon2-green{
fill: #008d46;
}
.icon2-red{
fill: #dc352f;
}複製代碼
<svg class="icon2 icon2-green">
<use xlink:href="#icon-increase"/>
</svg>
<svg class="icon2 icon2-red">
<use xlink:href="#icon-increase"/>
</svg>複製代碼
利用inherit
, 還能夠定義stroke-width
, stroke
等屬性.
除了對圖標總體顏色進行定義之外, 還能夠根據須要對圖形不一樣部分進行顏色定義. 這裏使用到了css 的自定義屬性(CSS Custom Properties).
這裏須要對icon.svg
進行修改, 將圖形個部分的顏色設置爲fill: var(--*[, default])
的形式.
<symbol id="icon-flag" width="150" height="100" viewBox="0 0 3 2">
<rect width="1" height="2" x="0" style="fill: var(--color0, #008d46)" />
<rect width="1" height="2" x="1" style="fill: var(--color1, #fff)"/>
<rect width="1" height="2" x="2" style="fill: var(--color2, #d2232c)"/>
</symbol>複製代碼
定義css樣式
.flag-belgium {
--color0: #201b18;
--color1: #f1ee3d;
--color2: #dc352f;
}複製代碼
<svg class="icon">
<use xlink:href="#icon-flag"/>
</svg>
<svg class="icon flag-belgium">
<use xlink:href="#icon-flag"/>
</svg>複製代碼
除此之外, 還有其餘一些樣式定義的形式, 更詳細的內容能夠閱讀Styling SVG Content with CSS.
上文介紹的是使用內聯svg, 但其實還可使用外部svg的.
<svg class="icon">
<use xlink:href="/res/svg/icon.svg#icon-flag"/>
</svg>複製代碼
然而這種方法不兼容IE9~10, 但若是非要使用外部svg的形式, 能夠引入一個pollyfillsvg4everybody, 當運行在不支持外部svg的狀況下, 這個pollyfill會經過異步請求加載svg委文件並將其注入到頁面當中, 將引用方法轉換成內聯svg.
能夠在svg.ftl
中定義一系列macro
, 用以加載.svg
文件.
<#macro svgicon path>
<#include "${path}">
</#macro>
<#macro svgicon3 >
<@svgicon "./icon3.svg"/>
</#macro>複製代碼
在頁面中引用demo.ftl
:
<@svgicon1/>
<svg>
<use xlink:href="#icon-italy"/>
</svg>複製代碼
xlink:href
是使用了命名空間的XML特性, 若是是寫在.html
頁面的標籤, 該特性可以正常被瀏覽器解析並完成svg渲染. 若是該svg變量是經過DOM API建立出來的話, 則須要使用特定的方法進行處理(SVG with USE tag not rendering).
即須要利用createElementNS
和setAttributeNS
方法在建立的同時聲明命名空間.
var use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-increase');
document.querySelector('#svgid').appendChild(use);複製代碼
只要是須要動態建立use
元素, 都須要使用上面這種方法才能使SVG Sprite中的元素實例化. 但在目前的Regular(0.4.3)中, 不會對命名空間進行處理, 這意味着, 若是直接將<svg><use xlink:href/></svg>
寫在Regular組件的模版中時, 該標籤是沒法正常渲染的. 爲此能夠增長一個指令r-xlink:href
以完成手動設置命名空間的操做.
Regular.directive('r-xlink:href', function (elem, val) {
if (val&& val.type === 'expression') {
this.$watch(val, function (newVal) {
elem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', newVal);
});
} else {
elem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', val);
}
});複製代碼
那麼在組件模版中就能夠像在普通.html
中那樣使用SVG Sprite了. 固然, 首先得確保SVG Sprite被寫到頁面中.
<svg>
<use r-xlink:href="#icon-italy"/>
</svg>複製代碼
在Regular的SVG 實踐中獲得了鄭海波大神的指點, 不然得繞更大的路才能把問題解決, 在此表示感謝.
對比前文提到的CSS Sprite和Icon Font, SVG有着明顯的優點:
雖然SVG Sprite有着高度的靈活性, 但於此同時, SVG兼容性有待考究, 同時其渲染性能也不及圖片和字體那麼高, 可能在某些狀況下不適用. 不過在通常的場景中, svg sprite還可以給開發帶來很大的便利的.