最近終于講完了Gemba Walk,終于有時間大把的時間好好補補最近落下的知識了。
背景描述
最近需要給項目中加上一個icon,第一反應就是問UX要個png的icon圖片,圖片拿上之后,上手就開始做。
這是第一次在某個repo工作,看完這個庫的pattern之后,猛然發現整個庫沒有一個png文件,全是svg,出于懶惰心里,全然沒有管,直接用了component中用了png文件。寫完發現都沒啥問題,行吧部署staging,等待第二天showcase。
第二天,果然,icon出不來了。。打開控制臺network:
- 圖片請求403,并且請求路徑是s3
- 手動打開aws看到這個bucket下竟然沒有這個圖片文件(原來是被打包坑了的。。。)
- 我氣沖沖的打開webpack配置文件,發現:
- png的loader是存在的。。。。
- 行8,本地build一下吧,發現,果然和webpack里配置的一樣,在build的結果目錄下一個images目錄下孤零零的躺著一個我的png icon
------------懵逼分割線
不得以,開始看部署文件。。。
- 發現package步驟不僅有webpack打包,還有
gulp publish
- 果然在gulpfile.js中發現,他們竟然只把我打包結果中的js和css文件作為result扔到s3上,根本沒有管images
本想氣沖沖的把打包結果中的images目錄扔到s3上,但是猛然覺得有點不對。。。諾大的項目中沒有一個png只有svg,這才是人家的pattern,然后引發了我幾個問題:
Q1: svg和png圖片的優劣都是啥,為什么有些項目不管什么類型的圖片都可以接受,但是有些項目必須要svg?
Q2: 使用webpack打包svg和png的異同?
Q3: 那么svg打包的結果也是單獨文件嗎?
.......
學習過程
瀏覽器對圖片的處理
對于瀏覽器而言,可以支持多種類型的文件:css/html/image
,那么圖片一般通過兩種方式其嵌入HTML:
- HTML tag
<img src=**/>
- 通過css中
backgroung: url(***)
那么src或者說url的參數中應該填寫什么樣的format呢?
- src/url的參數可以是Http URL
- src/url的參數也可以是Data URL
什么是Data URL?開發的時候應該選擇Http URL還是Data URL?
DataURL
-
What
DataURL:將文件通過某種編碼方式(可以使base64編碼)轉化成一串字符,瀏覽器能夠通過直接讀取字符還原文件。換句話說此處的URL不代表資源的地址,而直接是資源。
-
How
Data URLs 由四個部分組成:- 前綴(data:)
- 指示數據類型的MIME類型
- 如果非文本則為可選的base64標記
- 數據本身
data:[<mediatype>][;base64],<data>
data:image/gif;base64,**********
-
Why
我們所看到的網頁上的每一個圖片,都是需要消耗一個 http 請求下載而來的, 使用DataURL,圖片就可以跟隨HTML(<img>)或者css (background:url())一起被拿回來,不用重新發送請求了。
-
Pros
- 節省http請求(雖然CssSprites也可以)
- 沒有跨域問題
-
Cons
- 圖片被編碼之后,生成的字符串編碼大小一般而言都會比原文件大30%。如果把大圖片編碼到 html / css 中,會造成后者體積明顯增加,明顯影響網頁的打開速度。
- base64 無法緩存,要緩存只能緩存包含 base64 的文件(HTML/CSS文件)
綜上所述,如果圖片足夠小(比如icon)且無法被制作成雪碧圖(CssSprites),base64是個很好的選擇。
svg和png以及jpg的優劣
我們都知道,一個web項目能夠支持JPG/PNG/SVG
多種圖片文件格式,那么當我們需要圖片時候應該選用哪一種format呢?
那么問題應該什么樣的圖片能夠提升瀏覽器性能?
-
降低圖片的大小:
如果圖片使用HTTP URL,那么就意味著,瀏覽器需要發起HTTP請求獲取圖片,那么請求的response一定是盡可能的小才對。
- 雖然對于瀏覽器而言,是異步發送圖片請求(預加載),因此render tree的生成肯定不會等到圖片拿回,但是圖片如果很久之后才能獲取,可能導致頁面重新布局重新渲染。
方案:
可以選擇使用svg格式的圖片,svg生成的文件很小,下載很快 -
選擇適當的圖片寬度尺寸(即響應式圖片)
因為對于Mobile和Web端,圖片的分辨率要求不同而且尺寸要求也不同,因此根據不同的設備請求不同的圖片也是提升性能的一種方式。
如何實現呢?
- 通過css media實現
- Img的srcset和sizes的方法
- 通過picture元素,picturefill或平臺判斷來為不同終端平臺輸出不同的圖片
-
減少HTTP的網絡資源請求
如果圖片的總數量沒法改變,一個一個請求就意味著要發很多次HTTP 請求,那么將多個圖片作為一個response的結果就可以減少Http請求的數量,那么有什么方案能夠做到呢?
- 使用
Data URL
替代Http URL
- 合并圖片sprite(雪碧圖))
- 使用
-
圖片延遲加載(懶惰加載)
首屏不需要將所有圖片取回而是只把視窗內的圖片取回
不同的圖片format
- png:
- pros:
- 透明背景
- 支持高級別無損耗壓縮
- cons:
- 圖片尺寸相對較大
- pros:
- svg:
- pros:
- 透明背景
- 對于高分辨率設備表現很好
- 可編程
- pros:
- jpg:
- pros:
- 可以把文件壓縮到最小,適合應用于WEB圖片,可減少圖像的傳輸時間
- 可利用可變的壓縮比以控制文件大小
- cons:
- 不是透明背景,因此不適于做icon,線條
- 會造成質量下降,當您每編輯和重新保存 JPEG 文件時,JPEG 會混合原始圖片數據的質量下降。這種下降是累積性的、永久性的
- pros:
看起來svg簡直是完美,但是請注意png不能裝成svg,但是svg可以轉成png(質量降低)
------> 好了現在可以解釋,為啥我們項目的icon要使用svg了,圖片有小又是透明背景,秒殺我的png,那么為啥不選擇使用jpg呢?
圖片透明背景的意義
試想一個場景,一個icon他的格式是jpg(非透明背景),放在一個非白色背景上,然后出現這樣的場景
不對呀,怎么能是這樣!應該長這樣的啊
- 因此當你的圖中是icon或者是有鏤空的部分,必須選用透明背景格式的圖片
- 但是,當你的圖片是一張純背景,沒有鏤空,就可以選用jpg,比如背景圖片
webpack如何打包這些不同類型的圖片呢?
我們需要loader去處理這些圖片,不同的loader有不同的作用
url-loader:
將文件轉成base64編碼的DataUrl string, 根據上文所知:我們希望只有文件足夠小的時候被轉成base64,所以這個loader有兩個參數很重要:
- limit: 指明被轉成base64的文件最大尺寸
- 小于這個值的圖片被轉成base64,webpack會替換src的值成為base64編碼
- 大于這個值的圖片會被
file-loader
處理,并將這個loader的options轉給file-loader
- fallback: 指定一個當圖片尺寸大于limit時候使用的loader(不指定就是
file-loader
)
file-loader:
將圖片打包到某一個文件中,并替換src變成打包后圖片的Http URL,可以自定義圖片打包后的文件名和位置
svg-url-loader:
將文件轉成utf-8編碼的DataUrl string,和url-loader
不同不會轉成base64這樣做的好處是:
- 更小
- 瀏覽器更快的讀
- 壓縮的更好
和URL-loader
一樣可以設置limit確定什么樣大小的圖片可以被轉成DataURL什么樣的圖片使用file-loader
但是使用的過程中,這些option很重要:
- noquotes:true:在轉碼成DataURL的時候不要帶引號,保證DataURL一定能被瀏覽器解析成正確的svg圖片
- limit
-
iesafe:true
:只有這個屬性設置為true才能保證limit超過之后被file-loader解析