Web效能優化之圖片優化

前端兔子喵發表於2014-12-10

HTTP Archieve有個統計,圖片內容已經佔到了網際網路內容總量的62%,也就是說超過一半的流量和時間都用來下載圖片。從效能優化的角度看,圖片也絕對是優化的熱點和重點之一,Google PageSpeed或者Yahoo的14條效能優化規則無不把圖片優化作為重要的優化手段,本文覆蓋了Web圖片優化的方方面面,從基本的圖片格式選擇、到尚未被廣泛支援的響應式圖片均有所提及。

Google Web Fundamentals的說法我很喜歡:

圖片優化既是一門藝術,也是一門科學,圖片優化是一門藝術,是因為單個圖片的壓縮不存在最好的特定性方案,而圖片優化之所以是一門科學,是因為許多開發得很出色的方法和演算法可以明顯減小圖片的大小。要找到圖片的最優設定,需要按照許多維度進行認真分析:格式能力、編碼資料內容、畫素尺寸等。

真的要用圖片嗎?

要實現需要的效果,真的需要圖片嗎?這是首先要問自己的問題。瀏覽器和Web標準的發展速度極快,記得數年前我在用微軟Silverlight 1.0寫視訊播放器的時候,中文還不能使用自定義字型顯示,所以那時候寫了很多糟糕的程式碼把需要的文字在伺服器上生成圖片並快取起來。使用者下載起來很慢,搜尋引擎也完全無法檢索這些文字。

但是現在不一樣了,很多特效(漸變、陰影、圓角等等)都可以用純粹的HTML、CSS、SVG等加以實現,實現這些效果少則寥寥數行程式碼,多則載入額外的庫(一張普通的照片比非常強大的效果庫也大了許多)。這些效果不但需要的空間很小,而且在多裝置、多解析度下都能很好的工作,在低階瀏覽器上也可以實現較好的功能降級。因此在存在備選技術的情況下,應該首先選擇這些技術,只有在不得不使用圖片的時候才加入真正的圖片。

備選技術

  • CSS效果、CSS動畫。提供與解析度無關的效果,在任何解析度和縮放級別都可以顯示得非常清晰,佔用的空間也很小。
  • 網路字型。現在連很多圖示庫都是用字型方式提供,保持文字的可搜尋性同時擴充套件顯示的樣式。

前端工程師最好能和設計師、產品經理保持溝通,幫助他們瞭解到什麼樣的效果比較“簡潔、高效、可維護”,畢竟對於CSS來說改變圓角矩形的Radius可以實時看到效果,用圖片的話至少要重新生成圖片、切圖並替換資源。Retina、高解析度螢幕、多尺寸的裝置,這些都加快了非圖片特效的發展,想想在高解析度螢幕下Windows 7的慘不忍睹,就知道原生的圖片資源絕對不是多多益善。

圖片格式的選擇

如果效果真的需要圖片來表現,那麼選擇圖片格式是優化的第一步。我們經常聽到的詞語包括向量圖、標量圖、SVG、有失真壓縮、無失真壓縮等等,我們首先說明各種圖片格式的特點

圖片格式 壓縮方式 透明度 動畫 瀏覽器相容 適應場景
JPEG 有失真壓縮 不支援 不支援 所有 複雜顏色及形狀、尤其是照片
GIF 無失真壓縮 支援 支援 所有 簡單顏色,動畫
PNG 無失真壓縮 支援 不支援 所有 需要透明時
APNG 無失真壓縮 支援 支援 Firefox
Safari
iOS Safari
需要半透明效果的動畫
WebP 有失真壓縮 支援 支援 Chrome
Opera
Android Chrome
Android Browser
複雜顏色及形狀
瀏覽器平臺可預知
SVG 無失真壓縮 支援 支援 所有(IE8以上) 簡單圖形,需要良好的放縮體驗
需要動態控制圖片特效

其中APNG和WebP格式出現的較晚,尚未被Web標準所採納,只有在特定平臺或瀏覽器環境可以預知的情況下加以採用,雖然均可以在不支援的環境中較好的功能降級,但本節暫不討論這兩種格式。圖片格式選擇過程如下:

image optim

顏色豐富的照片,JPG是通用的選擇

  • 人眼的結構很適合檢視JPG壓縮後的照片,可以充分的忽略並在腦中補齊細節
  • JPG在壓縮率不高時保留的細節還是不錯的
  • WebP能夠比JPG減少30%的體積,但目前相容性較差

如果需要較通用的動畫,GIF是唯一可用的選擇

  • GIF支援的顏色範圍為256色,而且僅支援完全透明/完全不透明
  • GIF在顯示顏色豐富的動畫時可能出現顏色不全、邊緣鋸齒等問題

如果圖片由標準的幾何圖形組成,或需要使用程式動態控制其顯示特效,可以考慮SVG格式

  • SVG是使用XML定義的向量圖形,生成的圖片在各種解析度下均可自由放縮
  • SVG中可以通過JavaScript等介面自由變換圖片特效,可以完成其中部分元素的自由旋轉、移動、變換顏色等

如果需要清晰的顯示顏色豐富的圖片,PNG比較好

  • PNG-8能夠顯示256種顏色,但能夠同時支援256階透明,因此顏色數較少但需要半透明的情景(如微信動畫大表情)可以考慮PNG-8
  • PNG-24可以顯示真彩色,但不支援透明,顏色豐富的圖片推薦使用(如螢幕截圖、介面設計圖)
  • PNG-32可以顯示真彩色,同時支援256階透明,效果最好但尺寸也最大

圖片尺寸的選擇

尺寸,曾經是最不需要討論的話題,但自從Retina出現之後世界就變得複雜多了。關於移動裝置上的畫素和尺寸,展開說足夠寫一篇論文,我建議想詳細瞭解的同學參考下面的文章:

淺談移動Web開發(上):深入概念

這裡只說我們關心的部分和結論,我們需要分清不同型別的畫素:CSS畫素和裝置畫素。一個 CSS畫素可能包含多個裝置畫素。對於圖片來說,在高DPI的螢幕上需要使用解析度更高的圖片,如果我們討論的是Retina,那麼就需要2倍解析度(幾乎4倍尺寸)的圖片。這幾乎沒有取巧的空間,螢幕就是那麼大,需要的圖片也就是那麼大。(鴿子為什麼那麼大?^_^)

kraken

我們能夠控制的地方是“恰好”顯示所需尺寸的圖片。例如在螢幕中通過CSS或者標籤的wihth/height屬性,將一副200×200的圖片調整為100×100大小,那麼這其中就有(200×200)-(100×100)=30000個畫素是浪費的,這佔到了圖片尺寸的75%!

之所以有這麼大的浪費,是因為圖片的尺寸與面積基本成正比,與寬高的平方成正比。因此良好的計算客戶端實際顯示的圖片尺寸,能夠大大減小圖片的大小。即使只有長和寬都只有10px被浪費,但是當圖片足夠大時,這部分也將產生很大影響。

響應式圖片

上面提到“恰好”顯示客戶端所需大小的圖片,聽上去很容易不是嗎?但當響應式佈局出現後,這就變得極其困難。我們要支援上至1920寬度,下至320寬度的無數種裝置,如果使用1920寬度的圖片,那麼在小型裝置(這類裝置往往對網速和流量更加敏感)上每個使用者都要付出額外的頻寬和等待時間,如果使用320寬度的圖片,那麼在1920的螢幕上就像是在高清屏上使用DOS那麼讓人難以接受。

很自然的,我們需要圖片也能“響應式”載入,根據所在裝置的不同,載入不同尺寸的圖片。響應式圖片尚沒有寫入Web標準,實現起來也有諸多不便和相容性限制。我建議參考百度EFE團隊的這篇文章:

實戰響應式圖片

響應式圖片雖然尚未成為標準,但這是Web圖片優化的一柄利器,一旦被廣泛支援,再沒有比縮小圖片尺寸更有效的優化方法了。

優化JPG和PNG

選擇了正確的圖片格式,按照正確的大小生成了圖片後,我們還需要對圖片進行進一步優化,這種優化一般分兩步進行:

  1. 有損優化,刪除沒有出現或極少出現過的顏色,合併相鄰的相近顏色。這一步並不必須,如PNG格式就直接進入下一步
  2. 無損優化,壓縮資料,刪除不必要的資訊

JPG和PNG格式的圖片生成後,一般還有進一步優化的空間,例如JPG格式的照片中,可能攜帶有相機的Exif資訊,PNG格式的圖片中可能帶有Fireworks等軟體的圖層資訊等。去除這些額外資訊後,還可以通過減小圖片的調色盤,去除沒有出現過的顏色,以及合併相鄰的相同顏色等手段來進行優化。原理性的內容這裡不再贅述,僅介紹工程中可用的優化工具。

不同格式的圖片有一系列工具,這些工具有有更多種引數調節方案,常見的幾種調節工具有:

工具 用途
jpegtran 優化JPG圖片
OptiPNG 無損PNG優化
AdvPNG 無損PNG優化
PNGQuant 有損PNG優化

如果你真的需要追求各種圖片的極限壓縮,可以參閱這些工具的文件,但是對於一般的Web應用,面對的圖片種類多樣,幾乎不可能在工程中實現對每種工具的獨立配置,因此推薦使用以下工具來進行優化。這些工具往往使用了上表中的一種或幾種優化工具。

ImageOptim (Mac)

主頁:https://imageoptim.com/

Mac平臺下非常讚的圖片優化工具,只需要把需要優化的圖片拖拽進ImageOptim,就能夠完成對圖片的優化。設定選擇的也很豐富,目前支援JPG和PNG的優化。這是我在寫文章時最常用到的工具,把網站用到的圖片拖進去,優化就完成了~

image optim

Kraken (Web)

主頁:https://kraken.io/

在免費模式下可以上傳圖片,優化後打包下載,很多國外企業也選擇了它的收費服務。親自測試Kraken的圖片優化結果比ImageOptim一般要小3%左右,效果不錯,當然價格也不錯。適合偶爾有圖片優化需求,或者不在開發機上沒有優化軟體可以使用的情況。

kraken

智圖 (Web)

主頁:http://zhitu.tencent.com/

騰訊ISUX團隊有篇文章介紹智圖:http://isux.tencent.com/zhitu.html

國貨當自強,騰訊的智圖工具推出不久,但實測效果很好,而且提供了Gulp的自動化支援,這部分會在後面自動優化章節介紹。只想建議一句,Kraken的首頁比智圖美好幾百倍…… 而且把壓縮前的PNG和壓縮後的JPG放在一起對比大小,真的沒關係麼~

kraken

優化SVG

所有較新的瀏覽器都支援可縮放向量圖(SVG),SVG是基於XML的圖片格式,適用於二維圖片。可以將SVG標記直接嵌入網頁,也可以作為外部資源嵌入。可以通過大多數基於向量的繪圖軟體建立SVG檔案。這是一段簡單的SVG圖形:

kraken

這個圓形輪廓為黑色,背景為紅色,從Adobe Illustrator直接匯出。可以從中看到大量後設資料,例如圖層資訊、註釋和XML名稱空間等等,在瀏覽器中呈現資源時,通常不需要這些資料。因此我們需要使用一些工具去除這些不必要的後設資料,僅保留必須的標記。

SVGO工具可以縮減SVG檔案的體積,在這個的例子中,SVGO能夠將Illustrator生成的SVG檔案大小減小58%,從470位元組縮減到199位元組。

由於SVG是基於XML的格式,本質上是純文字,所以,還可以採用GZIP壓縮來減小傳輸大小,當然這需要一些伺服器配置,例如在apache伺服器中設定:

AddType image/svg+xml .svg
AddOutputFilterByType DEFLATE image/svg+xml

來對SVG檔案啟用GZip壓縮(當然你還需要先載入deflate模組並進行適當配置,GZip的配置超出了本文的範疇,這部分內容請自行Google)

優化GIF和APNG

GIF有很多好處,在顏色數較低的時候能夠大幅減小圖片體積,而且他也是唯一能夠較為通用的展示動畫的圖片格式。關於GIF格式的優化原理我並不熟悉,只是在工程中直接使用成型的壓縮工具,在後文自動優化章節的Grunt中,會介紹通過Grunt Task進行自動優化的方法。

關於APNG,目前瀏覽器對他的支援還不夠好,不過在支援HTML5的場景中,有成熟的開源工具apng-canvas可以用於支援APNG。

kraken

騰訊ISUX團隊有篇文章介紹iSparta工具:http://isux.tencent.com/introduction-of-apng.html。這是目前幾乎唯一能夠批量處理APNG檔案的工具,感興趣的同學可以在那篇文章裡得到更多地瞭解。

自動優化

前面說了太多關於如何優化各種不同格式圖片的方法和工具,優化圖片需要大量重複性的勞動,作為工程師顯然不會忍受這一點,因此也產生出了很多工具對圖片進行自動優化,這裡主要介紹CDN、Grunt/Gulp、Google PageSpeed三種方式。

自動優化:CDN

使用CDN對圖片自動進行優化,我在國外的CDN提供商處很少見到這類服務,倒是國內的兩大新秀CDN七牛和又拍在這方面都做了大量工作。其工作方式為,向CDN請求圖片的URL引數中包含了圖片處理的引數(格式、寬高等),CDN伺服器根據請求生成所需的圖片,傳送到使用者瀏覽器。

七牛雲端儲存的圖片處理介面極其豐富,覆蓋了圖片的大部分基本操作,例如:

  • 圖片裁剪,支援多種裁剪方式(如按長邊、短邊、填充、拉伸等)
  • 圖片格式轉換,支援JPG, GIF, PNG, WebP等,支援不同的圖片壓縮率
  • 圖片處理,支援圖片水印、高斯模糊、重心處理等

七牛雲端儲存的圖片處理介面使用並不複雜,例如下面這張原圖:

我們通過如下URL請求,裁剪正中部分,等比縮小生成200×200縮圖:

http://qiniuphotos.qiniudn.com/gogopher.jpg?imageView2/1/w/200/h/200

自動優化:Grunt/Gulp

這裡介紹用於圖片優化的Grunt元件:grunt-image。前端工程師的重複性工作,例如合併靜態資源、壓縮JS和CSS檔案、編譯SASS等都可以使用Grunt等自動化工具批量完成,圖片優化也是如此。

grunt-image非常強大,按照作者的介紹,其內部載入的圖片優化工具包括了pngquant, optipng, advpng, zopflipng, pngcrush, pngout, mozjpeg, jpegRecompress, jpegoptim, gifsicle和svgo。支援批量自動優化PNG, JPG, SVG和GIF,速度也不錯,配置方式支援單圖片優化和全目錄優化:

module.exports = function (grunt) {
  grunt.initConfig({
    image: {
      // 指定單獨的圖片優化
      static: {
        options: {
          pngquant: true,
          optipng: true,
          advpng: true,
          zopflipng: true,
          pngcrush: true,
          pngout: true,
          mozjpeg: true,
          jpegRecompress: true,
          jpegoptim: true,
          gifsicle: true,
          svgo: true
        },
        files: {
          'dist/img.png': 'src/img.png',
          'dist/img.jpg': 'src/img.jpg',
          'dist/img.gif': 'src/img.gif',
          'dist/img.svg': 'src/img.svg'
        }
      },
      // 指定圖片目錄進行優化
      dynamic: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: ['**/*.{png,jpg,gif,svg}'],
          dest: 'dist/'
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-image');
};

web image optimization

自動優化:Google PageSpeed

Google做事風格比較徹底,看見哪個軟體不好用就拿來直接fork出新版本或者乾脆重寫,對於Web優化,Google釋出了了Google PageSpeed這個伺服器模組,可以在apache或ngnix中載入,通過在伺服器配置檔案中進行設定來進行自動化的優化。對於圖片格式轉換、圖片優化甚至圖片LazyLoad都有相關選項。這部分展開會非常長,請感興趣的同學參考Google的手冊。

相關文章