原文連結:jiangxiaokun.com/web/2019/01…
緣起
Web
從誕生之日起是為了展示圖片
和文字
的,最典型的代表就是img
和span
。這是構建豐富的Web頁面的基石,也是理解瀏覽器表現(Browser performance
)的基礎。本文將從從圖片
中的小圖示
切入,介紹一下Web
中小圖示
的技術方案的演進。
Web中小圖示方案的演進
筆者本來打算從Image Sprites
,到 Svg Sprites
到iconfont
到 svg Icon
整體介紹一遍的,在查閱資料之後發現已經有大佬寫過了:Web中的圖示-大漠,介紹得算是很詳細(絕大部分應用場景都已經能覆蓋了),這一部分本文就不再贅述了。
筆者的補充
- MDN關於
Image sprites
的備註
:當使用 HTTP/2 時,使用多個小流量請求實際上可能更為頻寬友好。 DataURI
(圖片Base64
)(筆者的建議是慎用
,它可能成為一個效能瓶頸),因為CSS
在解析過程遇到Base64
,每次都需要解碼,這會阻塞關鍵CSS的渲染
,具體可以看這一篇文章:深挖 data URI 效能瓶頸
趁機糾正了自己之前的錯誤:
Gzip
是針對html/css/js
的,.wotf/.png/.ico
等圖片資源是不進行Gzip
壓縮,如果不確定可以檢視Network中的Response Headers
言歸正傳
接下來終於輪到了本文中的主角:Icon Font 登場了~~~。相比點陣圖 png Sprites
而言,使用字型圖示可以不受限於螢幕解析度
,而且字型圖示另一個優勢是:只要適合字型相關的CSS屬性
都適合字型圖示。筆者經過調研之後在專案中確定了 Icon font
的方案。
逝去的青春
最開始是將svg
上傳到 https://icomoon.io/
,生成對應的字型和樣式檔案,然後引入到專案中。
問題1:每次
update
圖示都需要重複上面的步驟,然後再把檔案下載下來,然後複製到專案原始碼中替換舊的檔案
問題2:樣式檔案不好管理,因為
icomoon
下載下來的樣式檔案因為相容性的需要,是需要進行修改的,以致於每次得摘出icon-list
, 原有已進行相容的程式碼保留。
問題3:當時
icomoon
免費版 沒有提供去色構建字型圖示的功能,導致還需要對生成的樣式進行一定的定製(調色,調位置)
問題4:更換了設計師之後,設計出來的
某些圖示檔案
引入之後,icomoon
生成的字型全部沒法用了。終於忍無可忍……
探索方案
因為源專案中使用gulp
和webpack
打包,心中最理想的方案當然是webpack
的plugin
或者loader
,或者gulp
的plugin
。嘗試過gulp-iconfont
結合gulp-iconfont-css
已經等等其他方案,要不是因為一些細節方面沒有配置成功,要不就是成功構建出來的字型圖片有明顯的偏移或者鋸齒。多番查閱資料和實踐之後終於發現了一個不那麼起眼的庫webfonts-loader
筆者曾經嘗試過的:gulp-iconfont、gulp-iconfont-css、webfontloader ……and so on.
webfonts-loader
第一眼見到他的時候,我未曾想過這將會是陪伴我許久的那一個,無論是從TA可憐的78❤️
,還是作者本人jeerbl
的知名度,但作為一個勇(zou
)於(tou
)嘗(wu
)鮮(lu
)的前端,還是認真地讀了一下TA
的README
,看到了熟悉的webpack
的loader
配置和js
的語法,決定好好地實踐一下。(扯遠了)
原理(工作流程)
webfonts-loader
(藉助webpack
)如何一步一步地將svg的圖示處理成我們最終想要的樣子?
How does the webfonts-loader which work with webpack build svg icons step by step ?
先來看最關鍵的3份配置:
scionfont.js
module.exports = {
files: [
'./svg/*.svg',
],
fontName: 'bicon',
classPrefix: 'bicon-',
fixedWidth: true,
types: ['eot', 'woff', 'ttf', 'svg'],
cssTemplate: './template.hbs'
};
複製程式碼
iconfont.js loader
{
test: /siconfont.js/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'webfonts-loader',
options: isProd ? {
fileName: assetsPath('img/[fontname]-[hash:7].[ext]')
} : {}
}
]
}
複製程式碼
fonts loader
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
複製程式碼
- 首先,webpack解析到
import './assets/fonts/siconfont.js'
, - 接著,webpack會將對應的
siconfont.js
載入到webpack的工作流中 - 而
siconfont.js
通過正則匹配到了對應的siconfont.js
的webpack相應的 loader(上面第2份配置
) - 首先使用
webfonts-loader
來處理這個xx.js
,webfonts-loader
解析這個siconfont.js
(上面的第一份配置
) 之後, 會將當前目錄svg
下的所有svg
圖示檔案都載入進來,並且將相應的CSS模板也載入了進來,並且通過一些項的配置
e.g:配置
types: ['eot', 'woff', 'ttf', 'svg']
,表示會打包出四種字型圖示檔案
- 接下來的步驟就簡單了:
webfonts-loader
處理完成之後輸出兩種檔案流:(1).eot/.woff
等字型檔案流 (2) 對應的關聯css流
- 檔案流下一步進入
css-loader
,該import
的import
,字型圖示路徑該resolve
的resolve
,還有其他可能需要的工作。 - 最終生成的
CSS
可能通過style-loader
直接內嵌到html 的style
標籤中,也可以通過Extract外掛
提取出來整合到最終頁面的CSS 中,然後通過link
使用
再一次感受到
webpack
自動收集依賴和管理依賴,真的是很強大,為我們省了太多心
大功告成
藉助著webpack
的熱更新機制,我們可以很方面地去更新svg資料夾
下的字型檔案,並即時使用。使用步驟:
- 拖入檔案
left-arrow.svg
- 在元件中對應DOM上新增類名(
class
):bicon-left-arrow
- 重新整理瀏覽器,字型圖示已經加上~
寫在最後
文中的方案已經在手機搜狐網和手搜體育頻道等多個專案中實踐和使用,能覆蓋絕大多數業務場景。文中完整的示例可以檢視 vue-ssr-start ,歡迎 star※
Vue-ssr-start 是我學習從零開始搭建一個
SSR
腳手架的理解和記錄,還有一些對前端工程化的思考和探索,會持續迭代並加上完整的註釋,歡迎watch
。水平有限,出錯難免,歡迎各位同學多多指正,共同進步~