- 原文地址:Native image lazy-loading for the web!
- 原文作者:addyosmani
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:nanjingboy
- 校對者:xionglong58, portandbridge
在本文中,我們將研究新的 loading
屬性,它為 <img>
及 <iframe>
帶來了延遲載入的能力。如果你對此感興趣,可檢視以下示例:
<img src="celebration.jpg" loading="lazy" alt="..." />
<iframe src="video-player.html" loading="lazy"></iframe>
複製程式碼
我們希望在 ~Chrome 75 中為 loading
提供支援,並且我們正在深入研究即將釋出的新特性。在此之前,讓我們深入瞭解它的工作原理。
簡介
Web 頁面通常包含大量的圖片,這些圖片將影響網路流量、頁面尺寸及頁面載入速度。這些圖片中許多處於螢幕外,往往需要使用者滾動頁面才能看到。
過去,為了降低螢幕外的圖片對頁面載入時間的影響,開發人員不得不使用 JavaScript 庫(比如:LazySizes)來推遲這些圖片的載入時機,直到使用者將頁面滾動到它們附近。
頁面載入 211 張圖片。沒有延遲載入的版本載入了 10 MB 資料。延遲載入版本(使用 LazySizes)僅預先載入了 250 KB 資料 - 其他圖片將隨著使用者的滾動而載入。檢視 WPT。
如果瀏覽器就能幫你做到避免載入螢幕外的圖片呢?這將有助於加快視窗中內容的載入、減少整體網路資料量以及低端裝置下記憶體使用量。因此,我很高興地告訴大家,很快就可以使用 image 和 iframe 的新屬性 loading
來實現了。
loading
屬性
loading
屬性允許瀏覽器推遲載入螢幕外的 image 和 iframe 直到使用者將頁面滾動到它們附近。loading
支援三個值:
lazy
:延遲載入。eager
:立即載入。auto
:由瀏覽器來決定是否延遲載入。
如果不指定該屬性,其預設值為 auto。
HTML 標準 正在研究將 <img>
和 <iframe>
的 loading
屬性作為標準的一部分。
例子
loading
屬性適用於 <img>
(包括包含 srcset
屬性及位於 <picture>
內部)和 <iframe>
:
<!-- 延遲載入螢幕外的圖片直到使用者滾動到它附近 -->
<img src="unicorn.jpg" loading="lazy" alt=".."/>
<!-- 立即載入(而非延遲載入)圖片 -->
<img src="unicorn.jpg" loading="eager" alt=".."/>
<!-- 瀏覽器決定是否延遲載入圖片 -->
<img src="unicorn.jpg" loading="auto" alt=".."/>
<!-- 延遲載入 <picture> 內的圖片。<img> 用來驅動圖片的載入,因此 <picture> 及 srcset
會將合適的圖片呈現在 <img> 上 -->
<picture>
<source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x">
<source srcset="small.jpg 1x, small-hd.jpg 2x">
<img src="fallback.jpg" loading="lazy">
</picture>
<!-- 延遲載入設定 srcset 屬性的圖片-->
<img src="small.jpg"
srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
sizes="(min-width: 36em) 33.3vw, 100vw"
alt="A rad wolf" loading="lazy">
<!-- 延遲載入螢幕外的 iframe 直到使用者滾動到它附近 -->
<iframe src="video-player.html" loading="lazy"></iframe>
複製程式碼
由瀏覽器完成“當使用者滾動到附近時”的確切檢測。一般來說,我們希望瀏覽器在快要進入視視窗之前便開始提取延遲圖片和 iframe 的內容。這將增加圖片或 iframe 在使用者滾動到它們時完成載入的更改。
注意:我曾建議應該將 loading
屬性值作為屬性名稱,因為它的命名與 decoding
屬性較為接近。在之前的提議中,類似 lazyload
這樣的屬性沒有被接受,這是因為我們需要支援多個值(lazy
、eager
及 auto
)。
特性檢測
我們已知道為延遲載入(跨瀏覽器支援)獲取及應用 JavaScript 庫的重要性。loading
的支援情況可以通過以下方式進行檢測:
<script>
if ('loading' in HTMLImageElement.prototype) {
// 瀏覽器支援 `loading`..
} else {
// 獲取並應用 polyfill/JavaScript 類庫
// 來替代 lazy-loading。
}
</script>
複製程式碼
注意:你還可以使用 loading
作為一種漸進的增強功能。支援該屬性的瀏覽器可通過 loading=lazy
獲得新的延遲載入能力,不支援該屬性的瀏覽器仍然會載入圖片。
跨瀏覽器的圖片延遲載入
如果跨瀏覽器支援圖片的延遲載入非常重要,那麼僅僅在使用 <img src=unicorn.jpg loading=lazy />
的標記中進行特性檢測、使用延遲載入庫是不夠的。
該標記需使用類似 <img data-src=unicorn.jpg />
(而非 src
、srcset
或 <source>
)的屬性,以避免在不支援新屬性的瀏覽器下觸發立刻載入。如果瀏覽器支援 loading
,可以使用 JavaScript 將這些屬性更改為正確的屬性,否則載入類庫。
下面是一個可以說明其可能是什麼樣子的例子。
- 視窗/一屏展示圖片是常規的
<img>
標籤。data-src
會破壞預載入掃描程式,因此我們希望避免它出現在視窗中的所有內容中。 - 我們在圖片上使用
data-src
以避免在不支援的瀏覽器中觸發立刻載入,如果瀏覽器支援loading
,我們將data-src
替換為src
。 - 如果
loading
不被支援,我們載入一個後備(LazySizes)指令碼並啟動它。在這裡,我們用class=lazyload
向 LazySizes 指出,哪些圖片要延遲載入。
<!-- 讓我們在視窗內正常載入這個圖片 -->
<img src="hero.jpg" alt=".."/>
<!-- 讓我們以延遲載入的方式載入剩餘圖片 -->
<img data-src="unicorn.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="cats.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="dogs.jpg" loading="lazy" alt=".." class="lazyload"/>
<script>
(async () => {
if ('loading' in HTMLImageElement.prototype) {
const images = document.querySelectorAll("img.lazyload");
images.forEach(img => {
img.src = img.dataset.src;
});
} else {
// 動態引入 LazySizes 庫
const lazySizesLib = await import('/lazysizes.min.js');
// 初始化 LazySizes(讀取 data-src & class=lazyload)
lazySizes.init(); // lazySizes 在全域性環境下工作。
}
})();
</script>
複製程式碼
示例
看看這個!一個 loading=lazy
示例,展示了整整 100 張小貓圖片。
詳見 YouTube 視訊:youtu.be/bhnfL6ODM68
Chrome 實現細節
我們強烈建議等到 loading
屬性處於穩定版本後再在你的生產環境中使用它。早期測試人員可能會發現以下註解非常有用。
立刻嘗試
轉到 chrome://flags
並同時開啟 "Enable lazy frame loading" 和 "Enable lazy image loading",然後重新啟動 Chrome。
配置
Chrome 延遲載入的實現不僅僅基於當前滾動位置的接近程度,還取決於網路連線速度。對於不同的網路連線速度,延遲載入 frame 和圖片的視窗距離閾值是硬編碼的,可以通過命令列覆蓋該值。以下是一個覆蓋圖片延遲載入設定的示例:
canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=5000,lazyImageLoadingDistanceThresholdPxOffline=8000,lazyImageLoadingDistanceThresholdPxSlow2G=8000,lazyImageLoadingDistanceThresholdPx2G=6000,lazyImageLoadingDistanceThresholdPx3G=4000,lazyImageLoadingDistanceThresholdPx4G=3000 'https://mathiasbynens.be/demo/img-loading-lazy'
複製程式碼
以上命令對應於(當前)預設配置。將所有值更改為 400
以便僅在滾動位置在距離圖片的 400 畫素以內開始延遲載入。下面我們還可以看到距離閾值設為 1 畫素的另一個做法(在本文前面的視訊中使用):
canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=1,lazyImageLoadingDistanceThresholdPxOffline=1,lazyImageLoadingDistanceThresholdPxSlow2G=1,lazyImageLoadingDistanceThresholdPx2G=1,lazyImageLoadingDistanceThresholdPx3G=1,lazyImageLoadingDistanceThresholdPx4G=1 'https://mathiasbynens.be/demo/img-loading-lazy'
複製程式碼
由於實現在未來幾周內穩定下來,我們的預設配置很可能會發生變化。
DevTools
Chrome 中 loading
的一個實現細節是它會在頁面載入時獲取前 2 KB 的圖片資料。如果伺服器支援範圍請求,則前 2 KB 可能包含圖片尺寸。這使得我們能夠生成/顯示具有相同尺寸的佔位符。如果像是圖示一類的資源的話,前 2 KB 也很有可能包含整幅圖片了。
Chrome 會在使用者即將看到圖片時抓取其剩餘資料。Chrome DevTools 中要注意的地方是,這可能導致(1)在 DevTools 的網路皮膚中“出現” 兩次獲取和(2)為每個圖片提供兩個請求的資源定時。
服務端確定 loading
支援
在一個美好的世界中,你不需要依賴客戶端上的 JavaScript 特性檢測來決定是否需要載入相容庫 — 你需要在提供包含 JavaScript 延遲載入庫的 HTML 之前處理此問題。客戶端提示可以啟用此類檢查。
傳遞 loading
引數的提示已經被考慮,但目前正處於早期討論階段。
總結
試試看 <img loading>
,並讓我們知道你的想法。我對大家如何探索跨瀏覽器的經驗,及是否有任何我們錯過的邊緣情況特別感興趣。
參考資料
感謝 Simon Pieters、Yoav Weiss 和 Mathias Bynens 的反饋。非常感謝 Ben Greenstein、Scott Little、Raj T 和 Houssein Djirdeh 在 LazyLoad 上的工作。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。