众所周知,性能優化一般就兩個東西,不加載和緩存。
當然不加載是不行的,所以今天就來講講延遲加載。
當前網頁除了大規模 JS 加載,還有一些我們可以進行優化的地方。
對於字體文件加載,可以看我的文章 - 字體模塊設計。
圖片加載#
圖片性能優化包含很多內容,包括壓縮、格式、用視頻替換 GIF、根據尺寸提供圖片、使用 WebP、使用 CDN。這些不是我們今天的內容,今天來看看圖片延遲加載。
最新的瀏覽器默認實現瀏覽器級別的延遲加載,可以使用 loading 屬性來開啟。
<img loading="lazy" />
我們還可以通過 IntersectionObserver 對象來開啟對 img 的延遲加載更精細的控制,例如在視口中出現 1 秒以上才開始顯示圖片。
// 獲取所有需要延遲加載的圖片元素
const lazyImages = document.querySelectorAll(".lazy-loaded-image");
// 設置IntersectionObserver的選項
const options = {
root: null,
rootMargin: "0px",
threshold: 0.5
};
// 創建IntersectionObserver對象
const lazyImageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
// 如果圖片在視口中出現1秒以上,開始加載圖片
setTimeout(() => {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}, 1000);
}
});
}, options);
// 觀察所有需要延遲加載的圖片元素
lazyImages.forEach((lazyImage) => {
lazyImageObserver.observe(lazyImage);
});
CSS 文件中的圖片#
CSS 文件中的圖片不可以用上面的加載方式,但是我們同樣可以使用視口監視的方式來動態添加類名已達到延遲加載圖片的目的。
.lazy-background {
background-image: url("hero-placeholder.jpg");
/* Placeholder image */
}
.lazy-background.visible {
background-image: url("hero.jpg");
/* The final image */
}
我們通過修改上面的代碼將 setTimeout 中的內容替換為(其他代碼相對應的改動)。
lazyBackGround.classList.add("visible");
來達到動態改變 CSS 加載的圖片方式實現延遲加載。
視頻的延遲加載#
視頻沒有 lazy 屬性,但是有個 preload 可以使用。
<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
這裡有個 poster 屬性,這個屬性非常有用,可以將圖片當作佔位圖來使用。
前文提到過,我們可以使用視頻來替換 GIF 顯示,這是因為相同內容,視頻相對於 GIF 有明顯的體積優勢。
這種場景下,我們的 video 標籤是這樣的:
這是一個延遲加載的自動播放,一直循環的視頻。
<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
<source data-src="one-does-not-simply.webm" type="video/webm">
<source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>
我們依然可以使用 IntersectionObserver 來動態地替換 source 元素的 src,來精細地控制延遲加載。
if (video.isIntersecting) {
for (var source in video.target.children) {
var videoSource = video.target.children[source];
if (typeof videoSource.tagName === 'string' && videoSource.tagName === 'SOURCE') {
videoSource.src = videoSource.dataset.src;
}
}
video.target.load();
video.target.classList.remove('lazy');
lazyVideoObserver.unobserve(video.target);
}
iframe 的延遲加載#
iframe 同樣支持 loading=lazy,最簡單的方法就是直接添加到標籤上,這對於頁面中嵌入大量視頻的場景非常有效。