網站應用性能下降的主因,以及 Lazy Loading 的必要性
現代的網站應用中,圖像是影響用戶體驗(UX)和網站性能的核心要素之一。隨著高解析度圖像使用的增加,以及頁面內圖片內容比重的上升,網站加載速度的下降已成為無法避免的問題。在初始加載時一次性加載所有圖片的方式會造成以下幾種致命的性能瓶頸。
-
初始加載時間增加 (FCP, LCP 延遲):通過下載視口外的圖片,使用者實際上看到內容的時間(First Contentful Paint)和最大內容元素加載的時間(Largest Contentful Paint)會顯著延遲。這也會對 Core Web Vitals 指標產生負面影響。
-
不必要的帶寬消耗:對於使用者不會滾動查看的圖片,也會浪費網絡資源,這在移動環境下會加重數據費用,而在桌面環境中則可能干擾其他重要資源的加載。
-
伺服器負擔增加:對所有圖片的請求同時發生,導致伺服器過載,這可能會影響服務的穩定性。
為了解決這些問題,最有效的策略之一就是 圖片 Lazy Loading。Lazy Loading 是一種技術,該技術會在用戶的視口(viewport)內進入或達到某個閾值時,異步加載該圖片,而不是在網頁初始加載時加載所有圖片。
圖片 Lazy Loading 的工作原理及應用方法
應用 Lazy Loading 的主要方式大致可分為兩種,需要根據各自的優缺點以及項目的需求來選擇。
1. 瀏覽器原生 Lazy Loading (loading="lazy"
)
最簡單且強大的方法是僅需在 HTML <img>
標籤中添加 loading="lazy"
屬性即可實施。最新的瀏覽器大多支持,瀏覽器本身以優化的方式處理 Lazy Loading。
<img src="placeholder.jpg"
data-src="actual-image.jpg"
alt="圖像描述"
loading="lazy"
width="500"
height="300">
-
優點:
-
易於實施:僅需添加 HTML 屬性而無需額外的 JavaScript 代碼即可實現。
-
性能優化:在瀏覽器引擎層面實施,因此比基於 JavaScript 的解決方案更高效且更快。
-
減輕開發者負擔:無需管理複雜的 Intersection Observer API 或事件監聽器,由瀏覽器自動處理。
-
-
缺點:
-
瀏覽器支持:可能在所有舊版瀏覽器中無法完全支持。(但大多現代瀏覽器均支持)
-
缺乏精細控制:開發者難以直接精細控制加載閾值(threshold)或加載策略。
-
建議:如果沒有特殊的控制需求,優先考慮使用原生 Lazy Loading。
2. 基於 JavaScript 的 Lazy Loading (使用 Intersection Observer API)
在需要更精細控制或需要對不支持 loading="lazy"
屬性的瀏覽器進行回退(fallback)時,可以實施基於 JavaScript 的 Lazy Loading。過去主要使用滾動事件監聽器,但因性能問題,現在標準已轉向使用 Intersection Observer API。
基本實現邏輯:
-
初始時,在圖片的
src
屬性中指定占位圖像,或將實際圖像 URL 存儲在data-src
屬性中。 -
創建 Intersection Observer 實例,並監視(observe)圖片元素。
-
當圖片元素進入視口或達到定義的閾值時,執行 Observer 回調函數。
-
在回調函數中,將存儲在
data-src
中的實際圖像 URL 移至src
屬性以加載圖片。 -
圖片加載完成後,停止對該圖片元素的監視(unobserve)。
// HTML (範例)
// <img class="lazyload" data-src="actual-image.jpg" alt="描述">
// JavaScript
document.addEventListener("DOMContentLoaded", function() {
const lazyImages = [].slice.call(document.querySelectorAll("img.lazyload"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
// lazyImage.srcset = lazyImage.dataset.srcset; // 如有需要也可以使用 srcset
lazyImage.classList.remove("lazyload");
lazyImageObserver.unobserve(lazyImage);
}
});
}, {
// Root Margin: 從視口邊緣提前加載圖像的區域 (px 或 %)
// 例如: "0px 0px 200px 0px" 是提前 200px 加載向下的圖像
rootMargin: "0px 0px 200px 0px"
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
// 為不支持 IntersectionObserver 的瀏覽器提供後備
// (例如:使用滾動事件監聽器,或立即加載所有圖片)
// 這部分在性能上不建議使用,應考慮主要目標瀏覽器進行判斷
lazyImages.forEach(function(lazyImage) {
lazyImage.src = lazyImage.dataset.src;
});
}
});
-
流行的 JavaScript Lazy Loading 庫:
-
lazysizes: 非常輕量,SEO 友好,並支持包括
srcset
和picture
元素在內的多種圖像格式。也可作為原生 Lazy Loading 的後備。 -
lozad.js: 以小的包體積和卓越的性能而著稱。
-
Lazy Loading 應用時的考量及優化建議
Lazy Loading 是一項強大的性能優化技術,但對所有圖像無差別地應用可能會損害用戶體驗。
- 管理 'Above the Fold' 圖像:對於初始屏幕(視口)中立即可見的圖片(Above the Fold),不應使用 Lazy Loading。這些圖片直接影響頁面的 Largest Contentful Paint(LCP),因此應明確標示
loading="eager"
或者將其排除在 Lazy Loading 之外以便立即加載。
<img src="logo.png" alt="公司標誌" width="100" height="50" loading="eager">
-
明確
width
和height
屬性:在 HTML 中明確指定圖像的width
和height
屬性,以避免佈局位移(Cumulative Layout Shift, CLS)。這樣可以使瀏覽器在圖像加載之前預留空間,防止加載時佈局晃動,這對提升 Core Web Vitals 分數至關重要。 -
使用占位圖像:為了在 Lazy Loading 圖像加載之前減少用戶看到的視覺空白,建議使用模糊的低解析度圖片或單色背景的占位符圖像。這樣可以通知用戶頁面正在加載中。
-
利用
srcset
和<picture>
標籤:與 Lazy Loading 一起使用響應式圖像(srcset
)和圖片引導(picture
標籤),以便提供適合不同屏幕大小和解析度的圖像,進一步減少不必要的圖像下載。
<picture>
<source srcset="image-large.webp" type="image/webp" media="(min-width: 1200px)" loading="lazy">
<source srcset="image-medium.webp" type="image/webp" media="(min-width: 768px)" loading="lazy">
<img src="placeholder.jpg" data-src="image-small.jpg" alt="描述" loading="lazy">
</picture>
結論:性能和用戶體驗,兩全其美的 Lazy Loading
圖片 Lazy Loading 不僅僅是延遲圖片加載,它是改進網頁初始加載性能、優化帶寬使用和減少伺服器負擔的必要網站優化技術。隨著 Core Web Vitals 等網站性能指標的重要性提升,Lazy Loading 的策略性應用已成為開發者必須考慮的事項。
在優先考慮原生 Lazy Loading 的同時,如果需要更精細的控制或需要支持特定瀏覽器環境,則應考慮使用基於 Intersection Observer API 的 JavaScript 實施或庫。此外,通過管理 'Above the Fold' 圖像、明確 width
/height
屬性以及使用占位符等優化建議,能夠為用戶提供快速而舒適的網絡體驗。
目前沒有評論。