就開開心心的用fontawesome不好嗎? 早點下班不好嗎?
icon的使用方法
相信大家在專案中若是需要使用icon的話,第一個一定會想到fontawesome, 他們的icon量非常多且齊全,且又能免費使用。
若是使用fontawesome時,icon會像這樣使用
<i class="fas fa-search"></i>
然後我們就能得到一個可愛的放大鏡小icon。
fontawesome - search icon
通常這種icon庫的做法是使用iconfont,font意思是字體,也就是說將icon作為一種字體來使用,因此,這些iconfont也能在css中被當作字體對待,可以套用像是color或fontsize等樣式變化。
但是其實在使用icon時,還有另外一種選擇 - SVG
什麼是SVG?
SVG, Scalable Vector Graphics, 可縮放矢量圖形,這種圖形其實是一行行的程式碼組成的,原理就是記錄這個圖形中一筆一畫(稱為path)的起始點和終點之間的向量,也因此這種圖片可以任意縮放而不會失真。
一個放大鏡的svg圖片會長這樣
1 2 3 4
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> </svg>
|
Material Design - search icon
沒錯,你可以直接把這段程式碼丟到html中,圖片就會出現了。
由於不屬於iconfont, 所以你不能像對待文字那樣操控它的樣式,svg的樣式必須透過特殊的語法操作, 像是stroke
, fill
等等(詳情可以參考MDN), 若是你把svg想像成用程式碼在畫布上繪圖, 可能會比較容易記憶這些語法。
使用SVG icon有什麼好處?
事實上,網路上已經有許多討論svg優於iconfont的文章了,我想我一定不能寫得比他們更好,因此我在這裡直接貼出來,若是你有興趣的話可以參考看看,或是google。
Inline SVG vs Icon Fonts - CSS Tricks
为什么要用SVG?svg与iconfont、图片多维度对比
… and more!
總結我讀過的文章以及個人體驗,svg icon有以下幾個優點:
利於SEO
svg可以像圖片一樣設定alt屬性, 因此搜尋引擎可以解讀它
不易破圖
svg就是一段段程式碼,只要放到code裡就會出現, 但是fontawesome有時卻會因為不明原因無法顯示(我太菜,真的不懂為什麼)
較輕量
使用iconfont會需要載入eot、ttf、woff等字體檔,但svg的話就不用
可客製化
事實上這是我開始研究SVG的主因, 由於公司的UI想要自己設計所有icon,主管又不想再使用第三方icon庫,最後想出來的解法就是使用svg來取代原有的iconfont
如何使用?
使用symbol & use
MDN - symbol
具體請見下例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 在頁面某處放置所有需要的svg <svg> 注意: 使用的是symbol標籤, 且有id作為辨識 <symbol id="search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> </symbol> </svg>
在需要的地方使用use <svg class="icon search"> href指向需要的icon的id作為定位 <use href="#search-icon"></use> </svg>
|
這種方式有個缺點,use標籤其實並不是正式的dom element, 而是shadow dom, 這種元素並不能被css操作, 因此不太方便
使用js做替換
這是目前我們公司使用的做法, 先將所有icon的svg都放置在一個叫iconmap.html的檔案中,先以ajax的方式呼叫後載入
1 2 3 4 5 6 7
| <div class="iconmap" style="display: none"> 存放的svg <svg id="icon-search" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> </svg> </div>
|
在iconmap載入後會使用js先爬梳過整個map, 將所有svg標籤以id為名稱, 值為svg的html內容,存成一個叫icon store的物件
類似這樣
1 2 3 4 5 6
| let iconstore = { search: `<svg id="icon-search" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> </svg>`; }
|
使用的方式是, 以特殊的標籤或class作為辨識, 告訴js這是一個需要被替換icon的元素, 接著在頁面載入時會爬梳整個dom, 找到需要被替換的icon動態進行替換
html結構
1 2 3 4
| <p> 使用一個客製化的tag作為辨識, class則是需要的icon名稱 我需要一個icon! <icon class="icon-search"></icon> </p>
|
公司是使用jquery
1 2 3 4
| $('icon').each(function(icon) { $(this).html(`${iconStore[$(this).attr('class').split('-')[1]]}`); })
|
這種方法是直接將svg替換元素, 因此可以用css操作
大概是這樣子做替換的,我們公司使用的是自己的一套框架,因此這邊寫的只是大致的實現思路,具體就不寫出來了
其實這個方法在實務上還有很多需要調整的地方,也踩過不少雷,到現在還不敢說很完善,像是有些時候需要icon動態切換, 或是iconmap載入的時機太晚而產生的icon缺失等等。若是你的網頁很靜態沒有很多js切換icon的動作的話,還是可以參考看看的
在php中使用
這是最近學習php後才會使用的辦法,參考的是這篇文章
原理跟第二種方法很像, 都是將icon統一存放在一個外部環境做動態替換, 不過這次是存成一個個php
icon-search.php
1 2 3 4 5 6 7 8
| <?php
echo '<svg class="icon-search" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M0 0h24v24H0z" fill="none"/> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> </svg>';
?>
|
html
1 2 3 4 5 6 7
| <div class="container"> <a href="search.php" class="navItemLink"> Search // 這個php區塊會被替換 <?php include("includes/icon/search.php")?> </a> </div>
|
這種方法我覺得也滿不錯的, 易讀且不易失敗, 但僅限php使用, 且組字串有點不方便
1 2 3 4 5
| echo "<p>這裡會有一個icon";
include("includes/icon/search.php");
echo "</p>";
|
基於echo中不能再包一個php區塊的緣故, 因此使用include, 導致字串會被切割開來, 若是html複雜的話就有點難寫
結果就會像這樣
總結
svg和iconfont其實都是很好的icon作法, 雖然現在很多呼籲svg取代iconfont的聲音, 但我認為iconfont親民好上手的特性真的很難取代。
若是你也在尋找使用svg替代iconfont的做法的話,希望這篇文章能成為一點參考,另外,搜尋inline svg
也可以找到許多不錯的文章。