使用 DATA URI 將圖片以 Base64 編碼並內崁至網頁中,加速載入速度

這裡介紹如何使用 Data URI 的方式減少 HTTP 的請求(Request)數量,讓網頁載入速度變得更快。

為什麼要使用 Data URI?

網頁的載入速度對於一個網站而言是很重要的,在載入一張網頁時,瀏覽器會針對網頁中的每一個元素都產生一個 HTTP 請求(request),使用這些請求來跟伺服器取得這些元素,而網頁中的圖片就是最常見的例子,如果網頁中包含很多圖片,那麼網頁在載入時就會產生很多的請求,情況就會像這樣:

http-reqeusts1

有一些網頁設計者會使用 CSS image sprites 的方式來避免產生過多的請求,而 Data URI 也是另一種很不錯的替代方案。

Data URI 是一種檔案格式,其資料全部都是經過 base64 編碼之後,以文字的方式來儲存的,這樣以文字方式儲存的好處就是可以直接寫進 HTML 或 CSS 中,不需要透過外部的檔案儲存。

Data URI 的格式長成這樣:

data:[<mime type>][;base64],<data>

下面這個是一張圖片使用 Data URI 的格式來表示的例子:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADoAAAA6CAYAAADhu0ooAAAFP0lEQVR4nO2bX0gcRxzH...[略]

後面的資料因為非常長,所以就省略了,下面這張圖就是使用 Data URI 來表示的圖片:


看起來跟一般的圖片其實沒什麼兩樣,但是因為這樣的方式是直接寫在 HTML 或 CSS 中,可以省去原本抓取該圖檔的請求。


這樣的 Data URI 表示除了用在圖片上之外,也可以應用於其他類型的檔案,甚至把一張 HTML 網頁使用這樣的方式放在另一張網頁中。

針對 iPhone 或是 iPad 所設計的網頁,通常會使用 SVG 圖檔以避免因為解析度不同而造成的模糊,而這樣的狀況亦可配合 Data URI 讓網頁的載入更順暢。

Data URI 的缺點

雖然 Data URI 可以減少 HTTP 請求的數量,但是也有一些缺點。

快取

一般網頁中的圖片都是使用個別的檔案儲存圖片,在這種情況下圖片與網頁是分開的,瀏覽器就可以對圖片做一些快取的動作,但是如果使用 Data URI,所有的資料都是在網頁中,就無法使用快取。

搜尋速度

由於經過 base64 編碼過後的資料通常會非常的長,如果把這麼長的文字直接寫進 HTML 網頁中,使用一般的文字編輯器在其中搜尋關鍵字時,就會變得比較慢(因為 HTML 網頁檔變得非常大),不過這個問題通常只會發生在網頁的開發者身上,一般使用者不會遇到這個問題。

如果想解決這個問題,可以試試看使用 SASS partial 的方式,將 Data URI 與一般的網頁分開,使用變數的方式引入,這樣就可以讓 HTML 網頁的程式碼保持很乾淨的狀態。

更新資料

因為 Data URI 是經過編碼之後儲存在 HTML 或 CSS 中的,所以如果這些資料要變更時,就要重新進行編碼,不過這個問題也可以使用 SASS 與 Compass 來處理,下面的會介紹如何使用使用這樣的方式來解決這個問題。

如何將資料編碼?

若要把一個檔案轉成 Data URI 的格式,方法有很多,除了手動轉檔之外,也可以寫成自動化的程式來處理。

線上編碼工具

如果你上 Google 搜尋這類的編碼工具,應該會發現非常多線上的編碼工具,而其中 dataurl.net 應該是最方便的工具之一,只要把想要進行編碼的檔案拖進去,馬上就可以得到 Data URI 的編碼結果。

dataurl_net

使用 PHP

如果你的網頁本身是使用 PHP 寫的,就可以考慮使用 PHP 內建的 base64 編碼函數 base64_encode(),例如:

<?php
function create_data_uri($source_file, $mime_type) {
  $encoded_string = base64_encode(file_get_contents($source_file));
  echo ('data:' . $mime_type . ';base64,' . $encoded_string);
}
?>

這裡定義了一個 create_data_uri() 函數,它可以將圖檔自動轉換為 Data URI 的格式,使用方式是這樣:

<img alt="Logo" src="<?php create_data_uri('logo.png', 'png') ?>" />

你甚至可以將這樣的 PHP 程式用於 CSS 檔案中,在 CSS 檔中使用 PHP 的方式可以參考 using PHP inside CSS

使用 Ruby And Rails

若要在 Ruby and Rails 中使用 base64 編碼的函數,必須要先引入 base64 這個函式庫,而其 create_data_uri() 函數寫法是這樣:

require 'base64'

def create_data_uri(source_file, mime_type)
  file_contents = File.open(source_file) { |f| f.read }
  encoded_string = Base64.encode64(file_contents)
  puts "data:#{mime_type};base64,#{encoded_string}"
end

使用方式是這樣:

<img alt="Logo" src="<%= create_data_uri('logo.gif', 'gif') %>;" />

使用 Compass 與 SASS

Compass 提供了一個很有用的函數 inline-image,如果你有使用 Compass 的話,就可以直接在 SASS 檔中使用這個函數:

body {
  background: inline-image("../images/logo.png")
}

因為這樣的方式是直接指向一個外部的檔案,所以如果該圖檔需要更動,也不會太麻煩,更換之後 Compass 會自動將新的檔案編譯成 CSS。

瀏覽器的支援

基本上現在大部分的瀏覽器都已經支援 Data URI 了,而 IE 9 因為一些安全性問題所以不支援,若要解決這個問題,可以使用 CSS 針對 IE 瀏覽器特別寫一個沒有使用 Data URI 的版本,或是使用 Progressive Enhancement 方式來處理。

效能

Data URI 已經被認為是一個減少 HTTP 請求的最佳方案,而經過測試確實可以得到不錯的效能。

雖然大部分的的情況 Data URI 可以加速網頁的載入,但是最近有一篇測試報告顯示在手持系統上,Data URI 比一般的網頁慢 6 倍,所以 Data URI 在使用上還是要依照自己的需求來考量。

參考資料:Frontcube

網頁開發

1 留言

  1. 附上Python的程式碼,感謝作者為我指引不少方向
    import base64
    import qrcode
    from io import BytesIO

    def str2base64pic(s:str):
    img = qrcode.make(s)
    buffered = BytesIO()
    img.save(buffered, format=”JPEG”)
    return base64.b64encode(buffered.getvalue()).decode(“utf-8”)

Comments are Closed