Device Pixel Ratio Header

之前文章有介紹過 DPR(Device Pixel Ratio),不過當時只能透過 JavaScript 在 client 端存取,如果 server 端要知道 client 端的 DPR 至少得要來回交換一次資訊,在那個時候就有想過應該之後會有新的標準來負責處理這個問題,而最近終於看到標準的草案了,叫做 HTTP Client Hints,照字面的意思,這個 HTTP 擴充標準不是只有 DPR,而是提供 client 端的一些資訊,目前包括了:

  • DPR
  • width
  • viewport-width
  • downlink

其中DPR就是 device pixel ratio;viewport-width就和以前介紹過的 viewport width 一樣;width比較特別,是實際希望的 resource 寬度,而不是真的屬於 device 的資訊,例如圖片在網頁內是 160px,裝置的 DPR 是 2,width就是 160×2 = 320px;最後一個downlink則是以前一直很難取得的網路速度,以前最大的限制在於不管是 client 端還是 server 端都很難取得實際的網路速度,雖然可以用 JavaScript 下載檔案算時間來取得素質,但是這樣的作法其實有個兩難的問題,一方面問題是如果檔案大小,那取得的數字會很不準確,另一方面問題是如果檔案太大,那必然就是浪費時間和網路頻寬,更不用說很多地方沒有吃到飽方案可以用,這樣的作法應該不會太受歡迎,甚至如果不測速度,搞不好都已經把網頁讀好了。現在把這個資訊的提供者更往上一層,改成由瀏覽器提供,瀏覽器就可以跟作業系統作溝通,就比較有機會不用先測速就拿到可以參考的網路速度。這些 Header 傳輸的時候都不用附上單位,只有數字,其中 downlink 的單位是 Mbps,而規範所希望瀏覽器提供的 downlink 數字是參考 Network Information API 這份 API 裡面整理的,主要連線方法的理論速度上限,例如 GSM 就是 0.01、LTE 是 100﹑wifi 802.11g 是 54,本來是想說這個數字是看瀏覽器自己決定,不只根據連線的方式,還會看實際的傳輸數字或是使用者偏好,例如他可能使用 LTE 但是因為不是吃到飽,所以希望把速度報低一點之類的。

Downlink 其實會比預期的還要有用,除了可以根據網路速度決定回傳的圖片大小外,還可以根據 downlink 大小來決定要回傳的 CSS,實際上使用可能像是,網路慢的時候就給出比較輕量的 CSS 回去給 client 端,用不一樣的版面呈現給使用者,有點像是 Google 的 Accelerated Mobile Pages Project 所做的。

Client hint header 是個需要 opt-in 的擴充功能,就是預設是沒開的,那要怎麼開啟呢,就是在網頁 document 的 header 加上Accept-CH

Accept-CH: "DPR, Downlink"

或是加上 meta tag

<meta http-equiv="Accept-CH" content="DPR, Width, Viewport-Width">

其中 equiv 是 equivalent 意思,就是和 HTTP header 等效的意思,透過這個 header 跟瀏覽器說 server 端可以接收 client hint 資訊,然後支援的瀏覽器就會在後續,這個網頁所需要用到的其它資源,像是 js, css, 圖片等等的 request 都加上這些資訊,這個溝通過程其實就是使用已經很久的機制: HTTP content negotiation,用的 header 也是Accept開頭的,目前已經支援的還只有 Chrome,而且要 46 版以後,其他幾個瀏覽器大多都還在討論要不要支援,Firefox 是有一些進度

這樣的設計其實有點先進,不完全是褒意,因為這意味著要 server 端,負責提供圖片的服務器,收到 request 後去看 DPR 或是 width 之類的資訊再來挑選要回傳哪一張圖片回去,而通常提供圖片靜態檔案的服務都不太有邏輯處理,大部分就是簡單的 HTTP server,只看靜態檔案,有就傳檔案回去,沒有就回傳 404,相信之後是會有些 module 或是設定的方法讓 HTTP server 可以把這部分直接處理掉,不過一些規模比較大的網站,如果有用上 CDN 的,可能就沒法直接用上這功能,還要等看有沒有 CDN 廠商支援。

Client hint 目前看來會是 responsive image 未來的一個主要解法,和 media query 相比其實有兩個很大的差異,第一個是 media query 是馬上(且隨時)發生效果,和 HTTP request 是無關的,所以一開始下載下來的網頁就會發生效果,但是 client hint 要透過第一個 HTML document 本身的 request 進行溝通,意味著 HTML document 本身的 request 是不會收到 client hint。第二個就是 media query 是隨時發生作用的,即使在網頁完整讀取下來後,還是有可能因為使用者造成的 client 環境變化,而讓瀏覽器去多下載一份檔案,最常見的情形就是調整視窗大小,在手機上可能就是轉直轉橫造成 viewport 寬度變化,甚至在 Mac 如果外接普通螢幕,拖拉瀏覽器視窗到不同螢幕也會造成影響,如果這些變化剛好符合設定的 media query,DPR 從 1 變成 2,就會讓瀏覽器又去下載了一張 DPR 不同的圖片,這類狀況在網路頻寬有限的環境下實在不是好事,而用 client hint header 的話就完全不會有這種狀況了,就只會有一開始帶著 Client Hint 去抓下來的那個檔案。

不過 Client Hint 也不是完全沒有副作用,目前最大的問題就是這幾個新 header 都不列在 simple headers 裡面,所以在做 CORS request 的時候,本來不用 preflight request 的都會變成需要 preflight request 了,這個問題其實現在還在討論,因為其實有很多類似的新 header 都會造成一樣的問題,像是 CSP、Server-Sent Events 裡面的 Event-ID,主要是這麼多 Header 進去,就不 simple 了,而且照最近標準發展的狀況來看,這份 simple headers 的清單很難固定不變,有興趣的可以跟一下討論