原文位址:Native image lazy-loading for the web!
原文作者:addyosmani
譯文出自:掘金翻譯計劃
本文永久連結:github.com/xitu/gold-m…
譯者:nanjingboy
校對者:xionglong58, portandbridge
在本文中,我們将研究新的
loading 屬性,它為<img>
及 `frameLabelStart--frameLabelEnd 我們希望在[ ~Chrome 75](https://link.juejin.im/?target=https%3A%2F%2Fchromestatus.com%2Ffeature%2F5645767347798016) 中為 loading 提供支援,并且我們正在深入研究即将釋出的新特性。在此之前,讓我們深入了解它的工作原理。
##簡介
Web 頁面通常包含大量的圖檔,這些圖檔将影響網絡流量、頁面尺寸及頁面加載速度。這些圖檔中許多處于螢幕外,往往需要使用者滾動頁面才能看到。
過去,為了降低螢幕外的圖檔對頁面加載時間的影響,開發人員不得不使用 JavaScript 庫(比如:LazySizes)來推遲這些圖檔的加載時機,直到使用者将頁面滾動到它們附近。
<p style="text-align:center">![image.png](https://ucc.alicdn.com/pic/developer-ecology/79b0d637ed03496c904f38ce3bbeeb2f.png)</p>
頁面加載 211 張圖檔。沒有延遲加載的版本加載了 10 MB 資料。延遲加載版本(使用 LazySizes)僅預先加載了 250 KB 資料 - 其他圖檔将随着使用者的滾動而加載。檢視 WPT。
如果浏覽器就能幫你做到避免加載螢幕外的圖檔呢?這将有助于加快視窗中内容的加載、減少整體網絡資料量以及低端裝置下記憶體使用量。是以,我很高興地告訴大家,很快就可以使用 image 和 iframe 的新屬性 loading 來實作了。
##loading 屬性
loading 屬性允許浏覽器推遲加載螢幕外的 `image` 和 `iframe` 直到使用者将頁面滾動到它們附近。`loading` 支援三個值:
lazy:延遲加載。
eager:立即加載。
auto:由浏覽器來決定是否延遲加載。
如果不指定該屬性,其預設值為 auto。
![image.png](https://ucc.alicdn.com/pic/developer-ecology/ca3483e5249b4f969f395823d3b94406.png)
[HTML 标準](https://link.juejin.im/?target=https%3A%2F%2Fgithub.com%2Fwhatwg%2Fhtml%2Fpull%2F3752) 正在研究将 `<img>` 和 `frameLabelStart--frameLabelEnd
由浏覽器完成“當使用者滾動到附近時”的确切檢測。一般來說,我們希望浏覽器在快要進入視視窗之前便開始提取延遲圖檔和
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 上的工作。
作者:淚已無痕
連結:
https://juejin.im/post/5cc183436fb9a032363936c3來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。