webp 是 google 提倡的一種新的 image 格式,意在爲 web 提供體積更小的圖片格式。一般狀況下,無損壓縮能夠減少 25%-35%
的體積(有例外狀況,反而會增大致積,可是是由於轉換圖片格式不兼容引發的),有損壓縮最大能夠節省大約 75%-90%
的體積。javascript
使用新的瀏覽器特性,首先應該考慮兼容性問題,它的兼容性以下圖:html
能夠發現,除了 ie 和 safari 以外,基本都支持了該格式,並且 safari 14 也即將支持該格式,到目前爲止,全球瀏覽器的 ~75.9%
(粗略統計) 份額的瀏覽器都可使用該功能。java
https://github.com/DonRai/react-image-webp/blob/master/modules/utils/index.js
核心代碼以下:react
const el = document.createElement('canvas') el.toDataURL('image/webp').indexOf('data:image/webp') === 0;
若是瀏覽器支持 webp
這種 mime-type
的話,則輸入的 base64
字符串會包含特定的關鍵字(這種手段也能夠用來檢測瀏覽器是否支持別的格式)。webpack
因爲能夠經過 js 來斷定瀏覽器是否支持該特性,因此問題也很好解決,只須要作一個邏輯斷定便可,好比:git
{ isWebpSupported() ? <img src={require('./path/to/img.webp')} /> : <img src={require('./path/to/img.png')} /> }
另外一種解決方案是,咱們把圖片的選擇邏輯,委託給瀏覽器,剛好 html 規範中,有一個 picture
標籤,這個標籤配合 source
和 img
標籤,能夠完美地解決這個問題,以下:github
<picture> <source srcset="logo.webp" type="image/webp"> <img src="logo.png" alt="logo"> </picture>
瀏覽器當遇到這段代碼時,會自動匹配 source
中的備選多媒體資源,儘量地使用最恰當的那一個資源。web
這裏可能有一個問題,就是 picture
標籤的兼容性問題,以下:canvas
能夠發現除了 ie
和 opera mini
均支持,因爲 ie
自己也不支持 webp
格式,因此咱們能夠忽略它。瀏覽器
CRA
自己已經支持 webp
格式的圖片,可是圖片須要是靜態的,即你首先應該有一個 webp
圖片,若是是對於將來的圖片,那沒什麼問題,但對於以前已經使用的圖片,就必須手動一張一張轉換,有點繁瑣,有沒有解決方案可以自動將以前的 jpg
或者 png
的圖片轉換爲 webp
格式,或者在打包時,同時生成一個 webp
格式的副本呢? 答案是有的,可使用 ImageminWebpWebpackPlugin
這個插件來完成這個工做,以下:
new ImageminWebpWebpackPlugin({ config: [ { test: /\.(jpe?g|png)/, options: { quality: 75, }, }, ], overrideExtension: true, detailedLogs: false, silent: false, strict: true, })
在 CRA 中,能夠經過 eject
或者 react-app-rewired
來覆蓋 webpack 配置,我這裏使用的是 customize-cra
這個庫中的 addWebpackPlugin
方法。
該插件的默認的生成規則是,xxx.png
在打包時,同時會生成一個 xxx.webp
的副本,固然這個規則也能夠在插件的配置中進行更改。
最後只須要把 img 元素簡易封裝一下便可,以下:
const WebpImage: React.FC< React.DetailedHTMLProps< React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement > > = props => { const { src } = props; const webpSrc = React.useMemo(() => { const nameChunks = src.split('.'); nameChunks.pop(); nameChunks.push('webp'); return nameChunks.join('.'); }, [src]); return ( <picture> <source srcSet={webpSrc} type="image/webp" /> <img {...props} /> </picture> ); };
這裏的封裝比較簡單,但做爲演示夠用了,效果以下:
network 中的加載狀況:
我示例中的圖片,源文件大小爲 184kb
,webp
副本文件大小爲 22kb
,以下圖:
因爲我這裏是有損壓縮,因此體積減小比例大概是 ~88%
,無損壓縮的話,會比這個低一些。
https://developers.google.com/speed/webp/
https://github.com/DonRai/react-image-webp
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture