首先要說的是,關於圖片的編碼原理,壓縮算法這些都是很專業的領域,做爲一個小前端來說,知道通常的應用場景和通常的特性就能夠了。css
矢量圖: 前端最多見的矢量圖是 SVG。關於 SVG 能夠看 SVG 基礎 這篇文章,SVG 適用於包含簡單的幾何圖形的圖像,由於 SVG 縮放不失真,因此 SVG 最適合用於高分辨率屏幕和須要以不一樣尺寸顯示的圖像。前端
柵格圖像:git
由於源數據太大,通常在網頁中使用的是通過壓縮的文件,下面是一個 JPG 文件的壓縮和解壓的過程:github
這裏涉及兩個過程:web
繼續以上面的 JPG 編解碼爲例。源數據是2 維「像素」柵格,好比,一個 10 × 10 的圖像便有 100 個像素。每一個像素又存儲了 RGBA 的值: (R) 紅色通道、(G) 綠色通道、(B) 藍色通道和 (A) alpha(透明度)通道。每一個通道 8 位,即每一個像素 4 個字節。 瀏覽器在拿到 jpg 文件以後,解碼獲得一個同原始數據同樣的像素柵格序列,也要爲每一個像素分配 4 個字節的內存(不管使用什麼格式傳輸,最後還原數據會和原始數據同樣大)。算法
那麼, 若是瀏覽器能夠解碼獲得原始數據,則爲無損壓縮。若是爲了獲得更小的文件,壓縮過程當中丟棄了一些信息,並且這個過程是不可逆的,那麼瀏覽器解碼也就沒法獲得原始數據,這種壓縮方式即是有損壓縮。chrome
對於柵格圖像要根據不一樣的使用場景選擇合適格式,接下來探究一些常見的這幾種圖片格式。後端
多是目前世界上使用最普遍的圖像格式,特色:瀏覽器
JPEG 適合於色彩豐富,線條感比較弱的圖片,好比大的背景圖,banner 圖等等。JPEG 是有損壓縮(也有無損的 JPEG,支持不夠普遍),壓縮時質量級別越低體積越小,圖片也越模糊。因此,在使用時,須要根據須要選擇合適的質量級別。緩存
JPEG 有多種不一樣的壓縮模式, 好比常見的基線(順序)JPEG 和漸進式 JPEG (PJPEG)。
基線 JPEG(大多數圖像編輯和優化工具的默認設置)以相對簡單的方式進行編碼和解碼:從上到下。 在鏈接速度緩慢或不穩定的狀況下加載基線 JPEG 時,用戶會先看到圖像的頂部,而後隨着圖像加載逐漸看到圖像的其餘部分。 盜用谷歌圖:
基線 JPEG 的加載方式是從上到下,而漸進式 JPEG 是從模糊到清晰。
漸進式 JPEG 將圖像分紅屢次掃描, 第一次掃描以模糊或低質量設置顯示圖像,後續掃描逐步提升圖像質量。 咱們能夠將這個過程看做「漸進式」提升圖像質量。 每次「掃描」圖像都會增長細節的清晰程度,最後合併爲全畫質圖像。
漸進式 JPEG 能夠在沒有下載完圖片就能夠看到最終圖像的大體輪廓,必定程度上能夠提高用戶體驗。
與基線 JPEG 相比,漸進式 JPEG:
使用基線 JPEG 相比仍是漸進式 JPEG,須要咱們根據場景選擇,在文件大小,網絡延遲和 CPU 消耗之間作一個權衡。
關於漸進式 JPEG 扯點別的: 漸進式 JPEG 採用的掃描算法有個學名 -- 隔行掃描,更多信息請看 維基百科 的介紹。
隔行掃描的效果是下面這樣的,感受這張圖專業並且很形象:
除了 JPEG 能夠支持隔行掃描外,PNG 和 GIF 也有支持,即是交錯式 PNG\GIF。
優勢:
缺點: 對於線條感較強,顏色對比強烈的圖,JPG 的壓縮一般會更易讓人感受到模糊;另外對於有透明度要求的圖 JPG 徹底無能爲力,這個時候咱們就要考慮 PNG 了。
特色:
由於 PNG 是一種無損壓縮的高保真的圖片格式(調色板大小的問題,下面討論),因此,能夠保存更多的細節,同時體積也就更大。
既然 PNG 是無損壓縮爲何一些工具還聲稱能夠壓縮 PNG 呢?好比最知名的 tinypng(也有人稱爲熊貓網)。
看看 tinypng 官網咋說的:
How does it work?
Excellent question! When you upload a PNG (Portable Network Graphics) file, similar colors in your image are combined. This technique is called 「quantization」. By reducing the number of colors, 24-bit PNG files can be converted to much smaller 8-bit indexed color images. All unnecessary metadata is stripped too. The result better PNG files with 100% support for transparency. Have your cake and eat it too!
這兒須要鋪墊一下 PNG 的三種形式:PNG8,PNG24 和 PNG32。 PNG8 和 PNG24 主要的區別有:
PNG24 與 PNG32:
咱們回過頭繼續說 PNG 的優化,正如 tinypng 官網所說,他們採用的優化即是把 PNG24/PNG32 轉爲 PNG8。這種優化方式也稱爲PNG 的有損壓縮。
日常使用中通常選擇使用 PNG8,若是 PNG8 的效果太差,則建議改成使用其餘格式,由於 PNG24 會大不少。
PNG 還有一個上文提到過的優化策略 —— 交錯式 PNG, 和漸進式 JPEG 的效果和原理相同,這裏就不過多介紹了。
概述:
對待 GIF 的原則通常是,除了動畫外不使用 GIF。由於,對於靜態 GIF 來講,PNG8 顯得更加優秀:
可是, PNG8 也並非總比 GIF 小,當圖片小到必定尺度的時候, GIF 會比其餘格式的圖都會小,好比: 這樣一張二維碼:
由於,二維碼只有黑色和白色,因此把調色板的顏色數量設爲 2, 導出 256 × 256 的圖(單位:像素):
導出爲 50 × 50 的圖:
GIF 以下,還能夠掃碼:
而當導出更小的圖時, GIF 的優點越明顯。當導出尺寸爲 20 × 20 的時候,兩者的體積就差了一倍。
由此,也就引出了 GIF 的另外的用途: 顏色簡單尺寸超小的圖,可使用 GIF,好比:
WebP 是由 Google 開發的一個年輕的圖像格式。同時, WebP 也是很優秀的:
因此咱們基本能夠認爲, 能使用 WebP 的時候就使用 WebP是一條頗有效的優化策略。
更多信息能夠看這裏Google I_O 2013 - WebP(感受視頻的字幕是校對過的,很準確)。
WebP 最大的問題是兼容問題:
從圖中能夠看到舊瀏覽器和蘋果家的產品基本不支持。
關於 WebP 的優化,基本就是解決兼容問題。
查看瀏覽器支不支持,最簡單的方法就是給 img 元素一個 .webp
的圖像(通常使用 1×1px 大小 webp 的 base64 字符串),看看是否能正常加載。基本原理以下:
var image = new Image();
image.onload = function() {
// 支持
};
image.error = function() {
// 不支持
};
image.src = 'data:image/webp;base64,xxxxx';
複製代碼
好比淘寶就在使用相似的技術,
<picture>
標籤HTML5 的 <picture>
給圖片的各類掃操做提供了可能。
<picture>
<source srcset="xxx.webp" type="image/webp">
<img src="xxx.jpg" alt="">
</picture>
複製代碼
對於上面的方案,仍須要前端去判別 jpg 和 webp。固然,這個判斷任務能夠由後端完成:
前端:
<img src="/xxx/avatar_url">
複製代碼
對於支持 WebP 的瀏覽器,在 HTTP 的請求頭中會包含:
Accept: image/webp,xxxxxxx
複製代碼
server 端據此返回合適的資源。
一般咱們從業務服務器只請求到了圖片的 URL,而圖片資源卻放在了 CND 上。這種狀況下可能須要業務服務器返回合適的 CDN 資源。 好比, YouTube 就是利用 AJAX 請求的 User-Agent
來判斷, 對於兼容 WebP 的瀏覽器返回 WebP 資源 URL。
目前不少 CND 都提供了 WebP 的格式轉換功能,經過參數能夠指定不一樣的格式。與上文提到的幾種方式搭配,口味更佳。好比淘寶:
chrome 中使用:
https://img.alicdn.com/xxxxxxxxx.jpg_.webp
複製代碼
在 IE 中使用:
https://img.alicdn.com/xxxxxxxxx.jpg
複製代碼
YouTube 也是相似,只不過圖片的 URL 是由後端直接返回,無需前端再拼參數。
另外,有些 CND 提供自動判斷功能,會根據狀況返回合適的圖片。這種狀況下,全部的格式轉換和兼容判斷問題由 CDN 完成,前端和後端,都無需在作額外的工做。
關於 SVG 基礎看SVG 基礎。
特色:
使用 AI 和 Sketch 中導出的 SVG 包含大量元數據,例如圖層信息、空屬性,多餘的空字、註解和 XML 命名空間等,這些在瀏覽器中都是不須要的。所以使用一些工具能夠去掉這些沒有必要的信息,好比SVGO。
另外,由於 SVG 是文本文件,因此可使用 GZIP 壓縮。
對於 SVG 我所知甚少,也就知道這些了。
現在手機屏幕的像素密度愈來愈高,各類設備的屏幕尺寸差異愈來愈大,咱們須要:
先看看MDN 文檔,若是看完文檔仍是有點懵逼,能夠再看看這篇大神的博客。
總結下基礎信息:
<img>
元素的屬性;舉個例子;
<img width="100px" src="./img/1.png" srcset="./img/1.png 1x, ./img/2.png 2x, ./img/3.png 3x" />
複製代碼
在 1x 的屏幕上顯示 1.png; 在 2x 的屏幕上顯示 2.png; 在 3x 的屏幕上顯示 3.png。其中 nx 指的是 DPR -- 設備像素比 (Device Pixel Ratio)。
再來個例子:
<img src="./img/1-1.png" width="30%" sizes="(max-width: 500px) 100px, (max-width: 800px) 200px, (max-width: 1200px) 300px" srcset="./img/1-1.png 100w, ./img/1-2.png 200w, ./img/1-3.png 300w, ./img/1-4.png 400w" />
複製代碼
不知到如何描述,仍是舉例說明吧: 若是使用寬爲 720px 普通 PC 瀏覽器(DPR=1)訪問,知足 (max-width: 800px) 200px
, 此時咱們指望圖片 CSS 尺寸爲 200px,由於 DPR == 1,因而,瀏覽器顯示一個 srcset 中 200 × 1 = 200w 的圖。 若是使用 ipad(屏幕寬度 768px, DPR=2)訪問,一樣知足 (max-width: 800px) 200px
, 一樣會得到指望圖片 css 尺寸 200px, 由於 DPR = 2,因而,顯示一個 srcset 中 200 × 2 = 400w 的圖。
<picture>
標籤<picture>
<source srcset="./img/2-3.png" media="(min-width: 800px)" />
<source srcset="./img/2-2.png" media="(min-width: 500px)" />
<img width="100px" srcset="./img/2-1.png" />
</picture>
複製代碼
<source>
標籤有 sizes 和 srcset 屬性,以及例程中的 media 屬性。
對於 CSS 中引用的圖像,也可使用響應式圖片:
<style> .img { height: 100px; width: 100px; background-repeat: no-repeat; background-size: cover; /**下面是主角**/ background-image: image-set( url('./img/1.png') 1x, url('./img/2.png') 2x, url('./img/3.png') 3x ); background-image: -webkit-image-set( url('./img/1.png') 1x, url('./img/2.png') 2x, url('./img/3.png') 3x ); } </style>
<div class="img"></div>
複製代碼
主流的瀏覽器在 2013 年左右就開始就開始支持了,目前來說兼容性還算能夠,不過還須要寫前綴。
與圖片相關的優化策略還有不少,下面簡單列舉一些,有機會再具體寫:
<link rel=preload>
; 提升圖片請求優先級。沒有萬能的優化策略,根據使用場景選擇最合適的優化便可: