Web 設計新趨勢: 使用 SVG 代替 Web Icon Font

來源:互聯網
上載者:User

標籤:

如果你還在使用 Icon Font 作為網頁中顯示表徵圖的實現方案,那麼你可能有點 Out 了。 由於使用 Icon Font 顯示表徵圖存在一些缺陷,開發人員們一直在致力於探索使用 SVG 作為替代的方法。 這篇文章列舉了目前 SVG 比較常見的使用方法。

關於使用 Icon Font 的缺陷,這篇來自 CSS Trick 的 《Inline SVG vs Icon Font》 可謂是總結的相當全面了。在我看來,Icon Font 的主要缺陷有以下幾條:

  1. 瀏覽器將其視為文字進行消除鋸齒最佳化,有時得到的效果並沒有想象中那麼銳利。 尤其是在不同系統下對文字進行消除鋸齒的演算法不同,可能會導致顯示效果不同。
  2. Icon Font 作為一種字型,Icon 顯示的大小和位置可能要受到font-sizeline-heightword-spacing等等 CSS 屬性的影響。 Icon 所在容器的 CSS 樣式可能對 Icon 的位置產生影響,調整起來很不方便。
  3. 使用上存在不便。首先,載入一個包含數百表徵圖的 Icon Font,卻只使用其中幾個表徵圖,非常浪費載入時間。 自己製作 Icon Font 以及把多個 Icon Font 中用到的表徵圖整合成一個 Font 也非常不方便。
  4. 為了實現最大程度的瀏覽器支援,可能要提供至少四種不同類型的字型檔。包括TTFWOFFEOT 以及一個使用 SVG 格式定義的字型。

開發人員們想出了多種使用 SVG 的技巧來解決 / 緩解上述問題,下面我們來逐個盤點目前常見的使用方法。

img/object 標籤

使用 img 和 object 標籤直接引用 SVG 是早期常見的使用方法。 這種方法的缺點主要在於要求每個表徵圖都單獨儲存成一個 SVG 檔案,使用時也是單獨請求的。 如果在頁面中使用的多個表徵圖,每個都是單獨請求的話會產生很多請求數,增加服務端的負載和拖慢頁面載入速度, 因此現在很少使用了。

不過,在 IE 中可以使用 object 標籤實現最後討論的 SVG Defs/Symbols 的效果。

Inline SVG

所謂 Inline SVG,就是直接把 SVG 寫入 HTML 中,這種方法簡單直接,而且具有最強的可調性。 使用這種方法,你可以使用 CSS 的fill屬性和stroke屬性來控制填充顏色和邊線的顏色, 如果 SVG 表徵圖包含多個部分,你甚至可以設定每個部分的樣式。同時,使用 JavaScript 修改 SVG 和產生動畫效果都可以實現。

Inline SVG 作為 HTML 文檔的一部分,不需要單獨請求。臨時需要修改某個表徵圖的形狀也比較方便。 但是 Inline SVG 使用上比較繁瑣,需要在頁面中插入一大塊 SVG 代碼因此不適合手寫,表徵圖複用起來也比較麻煩。

好在我們大部分的頁面都是由某種模板渲染出來的,無論是使用 PHP、Jinja2 還是 ERuby 範本語言, 都可可以定義一個函數來幫我們 include 這些 SVG。因此在很多情況下是很好的解決方案, 其不適合的主要使用情境就是純靜態頁面或者前後端分離用戶端頁面。

Data URIs

Data URIs 是一種不怎麼常見的技巧。之前我們在 CSS 裡定義元素的背景圖片時,常使用像下面這種方式

1234
.icon {  backgound-image: url(icons/a.png)  /* ... */}

而現在,url當中可以放置的可以不僅僅是指向資源的 URL 連結,而可以是資料本身。使用 Data URIs,無論是圖片還是 SVG, 你都可以將其編碼為 base64 並直接寫入 CSS。譬如

123
.icon{   background: url(data:text/svg+xml;base64,<base64 encoded data>)}

關於 base64 編碼,請參考wiki,Data URI 的格式定義如下

1
data:[<mime type>][;charset=<charset>][;base64],<encoded data>

使用這種方法,SVG Icon 使用起來和 Icon Font 一樣只需要為元素添加 CSS 即可,所有的資源都可以整合在一個 CSS 檔案中, 不需要額外引用 SVG 檔案。 如果你在使用 Gulp 或者 Grunt 這樣的 Build 工具,那麼將 SVG 整合到一個 CSS 當中是可以非常方便地自動化完成的。這個任務只有簡單的字串和編碼處理,基本不需要依賴非 JavaScript 的庫和資源。

使用這種方法的缺點是不能方便地使用 CSS 修改 Icon 的顏色和邊線屬性。

SVG Sprite

目前,一些提供製作 Icon Font 功能的網站 (如icomoon) 已經提供輸出 SVG Sprites 功能了。 SVG Sprites 可以看做上述 Data URIs 方法和之前使用位元影像的 Sprite 方法的組合。

在 Icon Font 還沒普及、表徵圖還主要依靠位元影像顯示的時候,前端工程師都會使用 Sprite 來減少圖片請求的次數。 其原理很簡單:將所有的表徵圖以一定的間隔排列起來組成一整張大圖片,使用時對於某個 Icon,編寫如下所示的 CSS。

123456
.icon-a {  background-image: url(/path/to/pic/contains/all/icons.png);  background-position: 0 120px !important;  width: 24px;  height: 24px;}

上述 CSS 通過設定background-position調整大圖片在背景中的位移,只將某個單個 Icon 暴露出來,其他部分都切掉。 對於所有的 Icon 都寫成這樣的 CSS 即可使用了。基礎的 SVG Sprite 其實只是將原來的位元影像改成了 SVG。

SVG Sprite 相比於原來的位元影像 Sprite 的一個優點就是可以通過 CSS 調整 Icon 顯示的大小。 使用時還可以 Fallback 到位元影像的 Sprite,因此有極好的瀏覽器安全色性。 不過和 Data URIs 方法一樣它同樣存在不能方便調整顏色樣式的問題。

目前輔助產生 SVG Sprites 的工具有 grunt-iconizr、 gulp-svg-sprites 等。 使用這兩個工具,只需將用到的 SVG 放到某個檔案夾中就可以自動被拼合成 Sprite 並輸出對應 CSS。 兩個工具都支援產生 PNG 格式的位元影像作為 Fallback,缺點是產生位元影像要依賴phantomjs這個重量級 JS 庫。

SVG Defs/Symbols

SVG Defs 和 Symbols 的原理類似,這裡著重介紹一下 SVG Symbols 的使用, SVG Defs/Symbols 本質上是對 Sprite 的進一步最佳化。之前,我們需要使用相對位置來控制哪個表徵圖被顯示出來, 但是其實 SVG 本身的定義允許你以某一種方式直接引用 SVG 中的某一部分。

將多個表徵圖整合成一個 SVG 中的多個 Symbols 之後是下面這樣的

1234567891011121314
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">    <symbol id="circle-cross" viewBox="0 0 32 32">      <title>circle-cross icon</title>      <path d="M16 1.333q2.99 0 5.703 1.161t4.677 3.125 3.125 4.677 1.161 5.703-1.161 5.703-3.125 4.677-4.677 3.125-5.703 1.161-5.703-1.161-4.677-3.125-3.125-4.677-1.161-5.703 1.161-5.703 3.125-4.677 4.677-3.125 5.703-1.161zm0 2.667q-2.438 0-4.661.953t-3.828 2.557-2.557 3.828-.953 4.661.953 4.661 2.557 3.828 3.828 2.557 4.661.953 4.661-.953 3.828-2.557 2.557-3.828.953-4.661-.953-4.661-2.557-3.828-3.828-2.557-4.661-.953zm3.771 6.885q.552 0 .948.391t.396.943-.396.948l-2.833 2.833 2.833 2.823q.396.396.396.938 0 .552-.396.943t-.948.391-.938-.385l-2.833-2.823-2.823 2.823q-.385.385-.948.385-.552 0-.943-.385t-.391-.938q0-.563.385-.948l2.833-2.823-2.833-2.833q-.385-.385-.385-.938t.391-.948.943-.396.948.396l2.823 2.833 2.833-2.833q.396-.396.938-.396z"/>    </symbol>    <symbol id="circle-check" viewBox="0 0 32 32">      <title>circle-check icon</title>      <path d="M16 1.333q2.99 0 5.703 1.161t4.677 3.125 3.125 4.677 1.161 5.703-1.161 5.703-3.125 4.677-4.677 3.125-5.703 1.161-5.703-1.161-4.677-3.125-3.125-4.677-1.161-5.703 1.161-5.703 3.125-4.677 4.677-3.125 5.703-1.161zm0 2.667q-2.438 0-4.661.953t-3.828 2.557-2.557 3.828-.953 4.661.953 4.661 2.557 3.828 3.828 2.557 4.661.953 4.661-.953 3.828-2.557 2.557-3.828.953-4.661-.953-4.661-2.557-3.828-3.828-2.557-4.661-.953zm4.49 7.99q.552 0 .943.391t.391.943-.396.948l-5.656 5.656q-.385.385-.938.385-.563 0-.948-.385l-2.833-2.823q-.385-.385-.385-.948 0-.552.391-.943t.943-.391.948.396l1.885 1.885 4.708-4.719q.396-.396.948-.396z"/>    </symbol>    <!-- .... --></svg>

每個 Symbol 設定一個 id 作為引用時的名字。使用 id 引用這個 SVG 中的 Icon 有兩種方式。

第一種,將上述 SVG 作為 body 的第一個元素插入在 HTML 中 (Chrome 存在一個 bug 導致不在這裡顯示不出映像), 此後,在需要顯示某個 Icon 的地方插入下面的代碼即可:

123
<svg class="icon">  <use xlink:href="#circle-cross"></use></svg>

這裡的use標籤直接使用#circle-cross這個 id 引用了 SVG 中的表徵圖。這種方式的瀏覽器安全色性較好。

我更喜歡的是第二種方式,這種方式不需要在 body 開始的地方插入 SVG,而是使用完整路徑引用 Icon。 也就是:

123456
<svg class="icon">  <use xlink:href="/img/posts/svg-icons.svg#circle-check"></use></svg><svg class="icon">  <use xlink:href="/img/posts/svg-icons.svg#circle-cross"></use></svg>

顯示出來的效果就是下面這個樣子 (可以使用瀏覽器的 Debug 工具來檢視下面的代碼)。

 

這種方式使用上跟img標籤沒有什麼太大的差別了。好處在於所有的表徵圖都在一個檔案中,因此只會請求一次。 這種不需要像 Sprite 那樣繁瑣的設定圖片的位移。使用 id 命名表徵圖並使用時直接使用 id 引用既直觀又簡單。 其靈活性和 Inline SVG 幾乎一樣——你可以設定顏色、邊線樣式、大小等等。 視瀏覽器的不同,有時你需要使用作為 SVG 標籤的開始。

1
<svg xmlns="http://www.w3.org/2000/svg">

對於 IE 則需要使用object標籤代替<svg><use>。關於相容性討論詳見 這篇文章。

除了前面提到過的幾個 Gulp 和 Grunt 的外掛程式都已經支援 SVG Defs/Symbols 了之外,這裡再推薦一個更輕量的 Gulp 外掛程式 gulp-svg-symbols。如果只使用 SVG Symbols 而無需 Sprite 支援, 那麼使用 gulp-svg-symbols 可以免去對 phantomjs 的依賴。

結語

SVG Icons 作為一種 Icon Font 的替代,使用上具有靈活性好、顯示效果好、可控性強等諸多優點。 尤其是最後介紹的 SVG Defs/Symbols 這種方式,已經讓 SVG Icon 變成了一種實用的解決方案。

瀏覽器安全色性是前端領域永恒的話題,目前來看對 SVG 的支援情況確實沒有 Web Font 那麼好, 其中,主流行動瀏覽器 (Safari, Chrome, IE for Windows Phone) 都已經基本相容 SVG, 但是案頭領域中仍然要面對 IE8 以下的瀏覽器,此外對 SVG Defs/Symbols 的支援也還存在差異。

現階段,如果對瀏覽器安全色性要求比較嚴苛 (主要是支援 IE6-8),則可以權衡考慮 Icon Font 和帶 Fallback 的 SVG Sprite。 否則的話,推薦使用 SVG Defs/Symbols 的方式代替 Icon Font。

個人認為 SVG Icons 已經具備普及的條件了。

Web 設計新趨勢: 使用 SVG 代替 Web Icon Font

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.