混合延遲加載:向原生延遲加載的漸進式遷移

已發表: 2022-03-10
快速總結↬原生延遲加載即將登陸網絡。 由於它不依賴於 JavaScript,它將徹底改變我們今天延遲加載內容的方式,使開發人員更容易延遲加載圖像和 iframe。 但這不是我們可以填充的功能,它需要一些時間才能在所有瀏覽器中使用。 在本文中,您將了解它是如何工作的,以及如何逐步將 JavaScript 驅動的延遲加載替換為原生替代方案,這要歸功於混合延遲加載。

在過去的幾周里,您可能聽說過或讀到過原生延遲加載,它將在接下來的幾個月中加入 Chromium 75。

“是的,好消息,但我們必須等到所有瀏覽器都支持它。”

如果這是您首先想到的,請繼續閱讀。 我會試著說服你相反的。

讓我們從原生延遲加載和優秀的 JavaScript 驅動的比較開始。

本機與 JavaScript 驅動的延遲加載

延遲加載是一種提高網站或 Web 應用程序性能的方法,它通過延遲首屏內容的加載來最大化首屏圖像和 iframe(有時是視頻)的渲染速度。

JavaScript 驅動的延遲加載

為了延遲加載圖像或 iframe,通過將適當的src屬性替換為類似的數據屬性data-src來標記它們是一種非常常見的做法,然後依靠 JavaScript 解決方案來檢測圖像/iframe 何時獲取靠近網站的可見部分(通常是因為用戶向下滾動)並將數據屬性複製到正確的屬性中,然後觸發其內容的延遲加載。

 <img data-src="turtle.jpg" alt="Lazy turtle" class="lazy">
跳躍後更多! 繼續往下看↓

本機延遲加載

根據本機延遲加載規範(仍在開發中),如果您想使用本機延遲加載功能延遲加載圖像或 iframe,您只需在相關標籤上添加loading=lazy屬性。

 <img src="turtle.jpg" alt="Lazy turtle" loading="lazy">

Addy Osmani 在他的文章“Native Image Lazy-Loading For The Web!”中廣泛地討論了這個主題。 他在其中表示,谷歌 Chrome 團隊已經在開發該功能,並打算在 Chrome 75 中發布。

其他基於 Chromium 的瀏覽器(如 Opera 和 Microsoft Edge)也將從這一開發中受益,因為它們在基於 Chromium 75 的第一次更新中獲得了相同的功能。

開始使用本機延遲加載

如果您的網站的圖像在頁面登陸時一次下載而沒有延遲加載,您可以在您的網站中啟用(在支持的情況下)本機延遲加載,就像添加 HTML 屬性一樣容易。 loading屬性告訴瀏覽器哪些圖像需要立即加載,哪些可以在用戶向下滾動時延遲下載。 相同的屬性可以應用於 iframe。

為了告訴瀏覽器一個特定的圖像很重要,以便他們可以盡快加載它,您必須在img標籤上添加loading="eager"屬性。 最佳做法是對主圖像執行此操作——通常是對將顯示在首屏的圖像。

 <img src="rabbit.jpg" alt="Fast rabbit" loading="eager">

要告訴瀏覽器應該延遲下載圖像,只需添加loading="lazy"屬性。 僅當您只對次要圖像執行此操作時,這才是最佳實踐——通常是那些將顯示在首屏下方的圖像。

 <img src="turtle.jpg" alt="Lazy turtle" loading="lazy">

只需將loading屬性添加到您的圖像和 iframe,您就可以讓您的網站使用本機延遲加載作為漸進式增強。 隨著大多數現代瀏覽器為您的用戶提供支持,您的網站將逐漸從中受益。

如果您的網站今天沒有使用任何類型的延遲加載,這是最好的方法,但如果您已經實現了 JavaScript 驅動的延遲加載解決方案,您可能希望保留它,同時逐步切換到本機延遲加載。

理想的解決方案是立即開始使用本機延遲加載,並使用 polyfill 使其適用於所有瀏覽器。 不幸的是,原生延遲加載不是我們可以用 JavaScript 進行 polyfill 的功能。

不使用 Polyfill

當一種新的瀏覽器技術發佈到單個瀏覽器時,開源社區通常會發布一個 JavaScript polyfill 來為其餘瀏覽器提供相同的技術。 例如, IntersectionObserver polyfill 使用 JavaScript 和 DOM 元素來協調Element.getBoundingClientRect()以重現原生 API 的行為。

但是本機延遲加載的情況不同,因為用於loading="lazy"的 JavaScript polyfill 必須阻止瀏覽器在圖像或 iframe 的標記中找到 URL 時立即加載內容。 JavaScript 無法控制頁面渲染的初始階段,因此無法填充原生延遲加載。

混合延遲加載

如果您對僅將本機延遲加載作為漸進式增強不滿意,或者您已經實現了基於 JavaScript 的延遲加載並且不想在不太現代的瀏覽器中失去此功能(但仍希望在瀏覽器上啟用本機延遲加載支持它),那麼你需要一個不同的解決方案。 介紹:混合延遲加載。

混合延遲加載是一種在支持它的瀏覽器上使用本機延遲加載的技術,否則依賴 JavaScript 來處理延遲加載。

為了進行混合延遲加載,您需要使用data屬性而不是真實的屬性來標記您的延遲內容(例如在 JavaScript 驅動的延遲加載中),並添加loading="lazy"屬性。

 <img data-src="turtle.jpg" loading="lazy" alt="Lazy turtle">

然後你需要一些 JavaScript。 首先,你需要檢測瀏覽器是否支持原生延遲加載。 然後,對每個具有loading="lazy"屬性的元素執行以下操作之一:

  • 如果支持原生延遲加載,則將data-src屬性值複製到src屬性中;
  • 如果不支持,請在元素進入視口時初始化 JavaScript 延遲加載腳本或插件以執行此操作。

自己編寫執行這些操作所需的 JavaScript 代碼並不難。 您可以檢測條件是否支持本機延遲加載:

 if ('loading' in HTMLImageElement.prototype)

如果是,只需從data-src複製src屬性值。 如果不是,請初始化您選擇的一些延遲加載腳本。

這是執行此操作的代碼片段。

 <!-- In-viewport images should be loaded normally, or eagerly --> <img src="important.jpg" loading="eager" alt="Important image"> <!-- Let's lazy-load the rest of these images --> <img data-src="lazy1.jpg" loading="lazy" alt="Lazy image 1"> <img data-src="lazy2.jpg" loading="lazy" alt="Lazy image 2"> <img data-src="lazy3.jpg" loading="lazy" alt="Lazy image 3"> <script> (function() { if ("loading" in HTMLImageElement.prototype) { var lazyEls = document.querySelectorAll("[loading=lazy]"); lazyEls.forEach(function(lazyEl) { lazyEl.setAttribute( "src", lazyEl.getAttribute("data-src") ); }); } else { // Dynamically include a lazy loading library of your choice // Here including vanilla-lazyload var script = document.createElement("script"); script.async = true; script.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"; window.lazyLoadOptions = { elements_selector: "[loading=lazy]" //eventually more options here }; document.body.appendChild(script); } })(); </script>

你可以在這個現場演示中找到並測試上面的代碼。

儘管如此,這是一個非常基本的腳本,當您使用其他屬性或標籤來獲取響應式圖像(例如srcsetsizes屬性,甚至是picturesource標籤)時,事情可能會變得複雜。

一點第三方幫助

在過去的四年裡,我一直在維護一個名為“ vanilla-lazyload ”的開源延遲加載腳本,在 Addy Osmani 寫了關於原生延遲加載的幾天后,社區的反應是問我的腳本是否可以充當 polyfill。

正如我之前解釋的,你不能為原生延遲加載功能創建一個 polyfill,但是,我想到了一個解決方案,它可以讓開發人員更容易開始過渡到原生延遲加載,而無需編寫任何 JavaScript 代碼我之前提過。

vanilla-lazyload版本 12 開始,您只需將use_native選項設置為true即可啟用混合延遲加載。 該腳本壓縮後只有 2.0 kB,並且已經在 GitHub、npm 和 jsDelivr 上可用。

  • 在 GitHub 上了解vanilla-lazyload

演示

您現在可以通過下載 Chrome Canary 或 Microsoft Edge Insider(開發頻道)然後啟用“啟用延遲圖像加載”和“啟用延遲幀加載”標誌來開始使用本機延遲加載。 要啟用這些標誌,請在瀏覽器的 URL 字段中輸入about:flags並在搜索框中搜索“lazy”。

原生延遲加載演示

要分析原生延遲加載在開發者工具中的工作原理,您可以從以下演示開始。 在這一節中,沒有使用任何一行 JavaScript 。 是的,這只是完全普通的原生延遲加載。

  • 測試原生延遲加載演示

預期結果:一次獲取所有圖像,但具有不同的 HTTP 響應。 帶有響應代碼200的那些是急切加載的圖像,而帶有響應代碼206的那些只是為了獲取有關圖像的初始信息而被部分獲取。 然後,當您向下滾動時,將使用200響應代碼完全獲取這些圖像。

混合延遲加載演示

要分析混合延遲加載的工作原理,您可以開始玩下一個演示。 這裡使用[email protected]並且use_native選項設置為true

  • 測試混合延遲加載演示

期待什麼:在不同的瀏覽器上嘗試演示,看看它的表現如何。 在支持本機延遲加載的瀏覽器上,該行為與本機延遲加載演示中的行為相同。 在不支持本機延遲加載的瀏覽器上,圖像將在您向下滾動時下載。

請注意vanilla-lazyload在後台使用 IntersectionObserver API,因此您需要在 Internet Explorer 和較新版本的 Safari 上填充它。 不過,如果不提供 polyfill 也沒什麼大不了的,因為在這種情況下vanilla-lazyload只會一次下載所有圖像。

注意:在vanilla-lazyload的自述文件的“To Polyfill or Not To Polyfill”章節中閱讀更多內容。

在您的網站中嘗試混合延遲加載

由於本機延遲加載即將在某些瀏覽器中出現,您今天為什麼不給它一個使用混合延遲加載的機會呢? 這是您需要做的:

HTML 標記

最簡單的圖像標記由兩個屬性組成: srcalt

對於首屏圖像,您應該保留src屬性並添加loading="eager"屬性。

 <img src="important.jpg" loading="eager" alt="Important image">

對於首屏圖像,您應該將src屬性替換為數據屬性data-src並添加loading="lazy"屬性。

 <img data-src="lazy.jpg" loading="lazy" alt="A lazy image">

如果您想使用響應式圖像,請對srcsetsizes屬性執行相同操作。

 <img alt="A lazy image" loading="lazy" data-src="lazy.jpg">

如果您更喜歡使用picture標籤,請同時更改source標籤中的srcsetsizessrc

 <picture> <source media="(min-width: 1200px)"> <source media="(min-width: 800px)"> <img alt="A lazy image" loading="lazy" data-src="lazy.jpg"> </picture>

picture標籤還可用於選擇性地為您的圖像加載 WebP 格式。

注意如果您想了解vanilla-lazyload的更多用法,請閱讀其自述文件的“入門”HTML 部分。

JavaScript 代碼

首先,您需要在您的網站上包含vanilla-lazyload

你可以從像 jsDelivr 這樣的 CDN 加載它:

 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"></script>

或者你可以使用 npm 安裝它:

 npm install vanilla-lazyload@12

也可以使用帶有自動初始化的async腳本; 使用type="module"將其加載為 ES 模塊或使用 RequireJS 將其加載為 AMD。 在自述文件的“入門”腳本部分中找到更多包含和使用vanilla-lazyload的方法。

然後,在您的網站/Web 應用程序的 JavaScript 代碼中,包括以下內容:

 var pageLazyLoad = new LazyLoad({ elements_selector: "[loading=lazy]", use_native: true // ← enables hybrid lazy loading });

注意腳本還有很多其他設置可以用來自定義vanilla-lazyload的行為,例如增加滾動區域的距離,從該區域開始加載元素或僅在元素停留在視口中時才加載元素給定的時間。 在自述文件的 API 部分查找更多設置。

一起使用async腳本

要將它們放在一起並使用async腳本來最大化性能,請參考以下 HTML 和 JavaScript 代碼:

 <!-- In-viewport images should be loaded normally, or eagerly --> <img src="important.jpg" loading="eager" alt="Important image"> <!-- Let's lazy-load the rest of these images --> <img data-src="lazy1.jpg" loading="lazy" alt="Lazy image 1"> <img data-src="lazy2.jpg" loading="lazy" alt="Lazy image 2"> <img data-src="lazy3.jpg" loading="lazy" alt="Lazy image 3"> <!-- Set the options for the global instance of vanilla-lazyload --> <script> window.lazyLoadOptions = { elements_selector: "[loading=lazy]", use_native: true // ← enables hybrid lazy loading }; </script> <!-- Include vanilla lazyload 12 through an async script --> <script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"></script>

而已! 通過這些非常簡單的步驟,您將在您的網站中啟用混合延遲加載!

重要的最佳實踐

  • 僅將延遲加載應用於您知道可能會顯示在首屏下方的圖像。 急切地加載首屏以最大限度地提高性能。 如果您只是對頁面中的所有圖像應用延遲加載,則會降低渲染性能。
  • 在加載圖像之前,使用 CSS 為圖像保留一些​​空間。 這樣,他們將推送下面的其餘內容。 如果您不這樣做,則更多的圖像將在它們應該被放置在首屏之前,從而觸發它們的立即下載。 如果你需要一個 CSS 技巧來做到這一點,你可以在vanilla-lazyload自述文件的提示和技巧部分找到一個。

優點和缺點

本機延遲加載
優點
  • 無需 JavaScript;
  • 沒有設置頭痛,它只是工作;
  • 無需使用 CSS 技巧為圖像預留空間;
缺點
  • 它今天不適用於所有瀏覽器;
  • 初始有效負載更高,因為每個圖像都預取了初始 2 kb。
JAVASCRIPT 驅動的延遲加載
優點
  • 它現在可以在所有瀏覽器中始終如一地工作;
  • 您可以進行高度自定義的 UI 技巧,例如模糊效果或延遲加載。
缺點
  • 它依賴於 JavaScript 來加載您的內容。
混合延遲加載
優點
  • 它使您有機會在支持的情況下啟用和測試本機延遲加載;
  • 它在所有瀏覽器上啟用延遲加載;
  • 一旦原生延遲加載支持廣泛普及,您就可以透明地刪除腳本依賴項。
缺點
  • 它仍然依賴 JavaScript 來加載您的內容。

包起來

我很高興原生延遲加載即將出現在瀏覽器中,我迫不及待地等待所有瀏覽器供應商實現它!

同時,您可以選擇豐富您的 HTML 標記以進行漸進式增強並僅在支持的情況下獲取本機延遲加載,或者您可以選擇混合延遲加載並獲取本機和 JavaScript 驅動的延遲加載,直到本機延遲加載的那一天絕大多數瀏覽器都支持。

試一試! 不要忘記在 GitHub 上加註星標/觀看vanilla-lazyload ,並在評論部分告訴我你的想法。

關於 SmashingMag 的進一步閱讀

  • 現在你看到我了:如何延遲、延遲加載和使用 IntersectionObserver 採取行動
  • 使用 ConditionerJS 延遲加載 JavaScript 模塊
  • 2019 年前端性能檢查表(PDF、Apple Pages、MS Word)
  • 提高網站性能如何幫助拯救地球