像 Medium 的漸近式圖片加載

/

English version:Progressive Image Loading like Medium

圖片延遲載入的 3 種方式

第一次知道有 Medium 這平台是上一份工作的時候,應該是 3 年前。當時看到他們文章內圖片加載是從霧到清晰的這個效果,有驚為天人的感覺。

當時只覺得這技術很厲害,因為那時對 JS 不熟,所以認為一定是什麼高科技技術。

最近在找資料時很常找到 Medium 上有人寫的文章,才又想起了這功能。

3 年後,我發現自己大概知道可以怎麼寫了,在一陣搜尋後看到了這篇:

Page Load Optimization by Progressive Image Loading (like Medium)

裡面說到圖片延遲載入有 3 種方式:

  1. 常見的 lazyload,就是滑到某個區塊後,那個區塊的圖片才開始載入。
  2. 像 Medium 的這種,其實跟 lazyload 很像,不一樣的是會先用一個佔位圖片放著,讓使用者以為圖片是慢慢讀取進來。
  3. Facebook 的那種,不過文章中沒說明 FB 是怎麼用的。

更驚人的是,文章中測試了一下 lazyload 跟 Medium 這兩個方式,Medium 的這種讀取速度更快。

看到這個比較,就想來寫一套自己可以用的圖片延遲載入。

這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝


Medium 漸進式載入的 3 個步驟

文章中作者也有提供他們的寫法,不過最近手上一個案子剛好有用背景圖去處理不同尺寸圖片的問題,就想用自己的方式去寫一個。

Medium 的這種漸近式讀圖,看上去很複雜,但看完文章後再思考一下,其很簡單,就三個步驟:

  1. 將原圖另外存一份寬度縮小到 10px,品質降成 10% 的小小圖,然後整個拉大撐滿原本要放圖片的地方,這種小小圖的大小不到 1kb。如果再狠一點,這個小小圖直接改放 base64,可以減少請求。
  2. 寫一段監聽滾動時的事件,當頁面捲動到圖片的區塊,就執行讀取原圖的功能,這邊直接使用套件「Waypoints」。
  3. 原圖讀完後,先把透明度調成 0,塞進有背景圖的區塊裡,因為區塊大小一開始就跟圖大小一樣,因此圖放上去後就會塞滿區塊。圖片放進去後,等個 50 毫秒就加入把透明度調回為 1 的 class,圖片就會有淡入效果。

以上就是思考過程,以下開始進入程式碼。


Medium 漸進式載入,實作程式碼部份

縮小圖的部份,用 Photoshop 來處理。

背景圖撐滿 div,還可以等比例縮放,這邊用的是一個 CSS 的特性:

Vertical padding is relative to element’s width not height.

簡單來說,就是 padding-toppadding-bottom 這兩個值如果用的單位是百分比(%),那它參考的是這個 div 的寬而不是高。

Bootstrap 的 Responsive embed 就是用這個特性去寫的。

以下是圖片區塊 div 的 HTML:

這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝

以下是我對背景圖撐滿 div 的 Sass 寫法:

因為 background-image 直接寫進 HTML: 裡了,所以 CSS 就處理 size 跟 position 這兩個即可。

要特別注意的是 height 要設成 0。

16:9、4:3 的比例,是 (16/9) * 100 來計算的,如果有圖片比例不是這兩種的情形,就改用 JS 去抓寬高後在丟進公式裡去計算就行。

接著是重要的 JS 了,直接引用了 jQuery,寫法上也用 ES6,如下:

第一步是先處理圖片不是 16:9 或 4:3 的狀況,會需要後端大大丟圖時一併丟圖的寬高,JS 才能抓值去計算 padding-bottom 的百分比。

第二步就是用了 Waypoints 這個套件,去監聽各個圖片區塊進入畫面了沒。

為了防止圖片區塊每一次滑動到都會執行功能,在最後要加上 destory() 把他取消掉。

第三步就是建立一個圖片物件,然後 append 進 div 中了。

原始檔放在 Github 上:

https://github.com/letswritetw/letswrite-medium-lazyload


實測頁面讀取時間

實際把頁面用 Pindom 去測試後,頁面讀取時間真的加快了。

下面這張是一般直接讀取圖片的數據,4.57 秒:

不做處理,直接讀取圖片
不做處理,直接讀取圖片

下面這張是用了延遲載入後的數據,降到 2.02 秒:

加了延遲載入的功能後
加了延遲載入的功能後

後來把功能 Demo 給了後端看,問說需不需要,得到的回應是,似乎大部份直接用 lazyload 就可以有效減少頁面讀取時間了,所以需求性沒很高。

覺得像 Medium 這種功能是對整體使用者經驗有特別要求的案子才會用到。

不過,也算是圓了 3 年前的夢,至少現在的我是有能力寫出來的。

頁面 Demo:像 Medium 的漸近式圖片加載

Summary
像Medium的漸近式圖片加載
Article Name
像Medium的漸近式圖片加載
Description
本篇大綱:圖片延遲載入的3種方式、Medium漸進式載入的3個步驟、Medium漸進式載入,實作程式碼部份、實測頁面讀取時間。實際把頁面用pindom去測試後,頁面讀取時間真的加快了。下面這張是一般直接讀取圖片的數據,4.57秒,下面這張是用了延遲載入後的數據,降到2.02秒。
Augustus
Let's Write
Let's Write
https://letswrite.tw/wp-content/uploads/2020/08/logo_512.jpg

隨選筆記文

Front-End

postMessage:主頁、iframe 頁可互相傳值

Bot Telegram

Telegram Bot 學習筆記 – 1:用 GCP + Node.js 接收 / 推播訊息

Front-End

如何用 Netlify CMS 製作電子報生成器

Bot Telegram

Telegram Bot 學習筆記 – 5:取得使用者大頭照

Bot Telegram

Telegram Bot 學習筆記 – 4:命令列 Commands

Vue

Vue CLI 安裝 Tailwind CSS

Bot LINE

LINE Bot:用 Google Apps Script 建立簡易網站監測機器人

API

如何用 Postman Mock Server 快速建立 API Server

Bot LINE

用 LINE Bot API 建立 LINE@ 圖文選單

PWA

PWA 學習筆記 – 5:用 Firebase 做 Web Push

以下是留言,但關於留言的部份必需先讓你們知道:

本站的文章都是 Augustus 因為覺得有趣,才會實作並整理成筆記文而後進行發表。

如果留言是希望把 Demo 改成「你想要」的樣子,或是把功能改成「符合你需求」的樣子,

Sorry~ 除非那修改是 Augustus 也有興趣的,不然不會幫你們寫程式去面對工作或是交作業。

未來這類的留言不會再主動回覆。😎

另外,公開信箱是為了讓金流驗證用,

因為之前遇過幾次回信協助解決問題後,對方卻一聲謝謝也沒有,就這樣拿去幫工作交差。

因此決定不再回覆信件,有疑問就利用留言功能囉。

訂閱
通知
guest
2 Comments
最舊
最新
Inline Feedbacks
看所有留言
otis
otis
1 年 之前

請問那個可以測量圖片速度的網站是哪個?