這裡介紹如何使用 Data URI 的方式減少 HTTP 的請求(Request)數量,讓網頁載入速度變得更快。
為什麼要使用 Data URI?
網頁的載入速度對於一個網站而言是很重要的,在載入一張網頁時,瀏覽器會針對網頁中的每一個元素都產生一個 HTTP 請求(request),使用這些請求來跟伺服器取得這些元素,而網頁中的圖片就是最常見的例子,如果網頁中包含很多圖片,那麼網頁在載入時就會產生很多的請求,情況就會像這樣:
有一些網頁設計者會使用 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 的編碼結果。
使用 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
黃彥儒
附上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”)