#2523 提到了圖片自動轉檔,自用隨便改是很簡單沒錯,但是維護了一段時間之後現在看到任何 feature request 都覺得怕,一個 feature 後面可是會接著一堆向前兼容、無數的程式碼除錯、用戶抱怨和無止盡的 enhancement request 的,所以 survey 了一下發現確實有人做了圖片轉檔 module,這樣就不用自己寫了。
hugo-responsive-images 是一個已經迭代三年的 Hugo 圖片自動轉檔工具,看起來幾乎是把所有 Hugo 的影像功能幾乎都用上了,我在 Hugo 文檔看感覺都沒那麼多東西,不過這篇文章的目的不是要稱讚他,因為 hugo-responsive-images 的文檔有寫但不多,具體怎麼用需要靠直覺猜,本文的目的就是簡單記錄如何使用。
安裝
hugo-responsive-images 一定只能使用 Hugo moduless 方式安裝,包含你原本使用的主題也要改用 Hugo moduless 方式安裝,這裡我以 Blowfish 主題為例示範全新安裝的步驟。
步驟
- 請先準備好必要依賴 Hugo + Go
- hugo new site
test_site
- cd
test_site
- rm
hugo.toml
- 到 Blowfish release 頁面 下載 config-default.zip
- 解壓縮到專案根目錄
- 把
config/_default/hugo.toml
轉為 yaml,網路上有轉換工具 - 在
config/_default/module.toml
貼上主題設定:
|
|
- 在
config/_default/hugo.yaml
貼上測試用的圖片轉檔設定,之後可以自行調整:
|
|
- 建立你的 markdown 檔案和圖片,這樣就可以直接使用 markdown 語法載入圖片了。
說明
為何安裝要搞的這麼多步驟?主要是因為 hugo-responsive-images 裡面又引用了其他東西,所以即使使用雙主題方式也無法達成,一定要使用 Hugo modules 才能安裝。
要轉成 yaml 的原因是 Hugo 以 toml 讀取 widths: [500, 1000]
的 toml 版本時把他轉成字串了,我懶的處理這個問題直接把設定檔轉 yaml 比較快。
報錯內容
Invalid config "width in widths slice" value of "600" for picture render-hook image /posts/hello/image-resizing.png on page /posts/hello/. Must be an integer. <-- 被辨識成字串而不是數字
渲染結果
以一張 2400x1350 的 PNG 圖片為例為例,原始大小 99KB,經過 hugo-responsive-images 轉換後的 HTML 如下:
|
|
可以看到兩個 source 分別是 webp 和 png 版本,瀏覽器會由上往下找看你的裝置支援哪種就套用,也就是說會先看裝置是否支援 webp,如果不行的話就 fallback 成 png 格式。source 標籤中的 srcset 代表根據你的裝置(不只是參考解析度)選擇載入最適合的圖片,sizes 設定很複雜,請看文檔說明,這裡不多做介紹。
- Using responsive images in HTML:入門教學
- <img>: The Image Embed element:整個 img 標籤的文檔,裡面有說明 sizes / srcset / loading 三個參數的交互
- HTMLImageElement: srcset property :srcset 屬性的文檔
- HTMLImageElement: sizes property:sizes 屬性的文檔
外行人看 srcset
我不是前端工程師,但是稍微說說我對 srcset 的理解。
我能保證你看完這些文檔還是不會設定,因為他實際上的邏輯是這樣:
iPhone 16
Viewport Size
= 393px × 852px,DPR
= 3從左到右檢查 sizes 屬性的每個條件,第一個符合的就使用:
- (min-width: 1280px) → 檢查 393px ≥ 1280px?否,繼續
- (min-width: 853px) → 檢查 393px ≥ 853px?否,繼續
- (min-width: 648px) → 檢查 393px ≥ 648px?否,繼續
- 100vw → 這是預設值,使用此項
計算實際寬度
100vw = 100% × 393px = 393px
計算實際所需的物理像素寬度 =
393px × 3 = 1179px
從 srcset 中選擇最適合的圖片
- 500px < 1179px ❌
- 1000px < 1179px ❌
- 1500px ≥ 1179px ✅
單看 MDN 文檔你絕對不可能正確設定這個東西,因為他的設計不單純只是節省流量,也考慮在不同響應式視窗中使用不同的圖像佈局,例如大螢幕可能有三欄,反而不需要大圖,稍微小一點的螢幕變成一欄,這張圖片顯示寬度反而變大了,所以事情才搞的這麼麻煩,如果把他理解成節省流量,那絕對搞不懂這些參數為何這樣設計。
建議參考 web.dev 的說明比 MDN 更清楚:
還有一個賣 web performance 的網站寫的文章,說的很詳細,不過被我抓到有一個地方和 MDN 說的不一樣,MDN 總是建議你使用 width / height,但是他說使用 w descriptor 就不建議使用 width / height property。
最後是一些關於 srcset 的筆記
- sizes 屬性要和 srcset 同時出現才可協同運作,不過你沒寫的話我測試瀏覽器還是會自動幫你做
- sizes 屬性「應該不影響瀏覽器佈局」,沒有百分百確定
- 使用
loading="lazy"
可以啟用sizes="auto"
選項,但是此選項支援不多,不過就算沒寫,承 1,瀏覽器還是會幫你做 - w descriptor 文檔說明他的值應該要和圖片寬度完全相同,但實際上不用,因此可以做一個 hack,直接不寫 sizes,並且把 w descriptor 的值改成你想要的大小,就不用絞盡腦汁考慮每個裝置對應 sizes/srcset 這個複雜的查找流程
- x descriptor 是廢物,沒有任何理由用他,手機通常是 high DPR,電腦通常 low,但是也可以 high,因此用 x descriptor 一點用都沒有
- 如果只是簡單的想要在不同 CSS pixel 使用不同圖片,直接用 picture 標籤搭配 source,這樣超簡單
- 完全找不到有人討論 sizes 的 media query 應該用哪種方式最好,我看 pixel 對比使用 em 約 7:3
- AI 給的資訊大錯特錯,即使給他文檔他還是跟你說錯誤資訊,狗畜牲