天天看點

[譯] 原生實作圖檔懶加載

原文位址: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

來源:掘金

著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

繼續閱讀