圖片往往是影響網頁載入速度的主要因素之一。本文整理七種圖片懶加載技術,比較各自的相容性與效能取捨,方便依場景選用。

什麼是圖片懶加載?

圖片懶加載是一種網頁優化技術,延遲載入暫時不可見的圖片。只有當使用者滾動到圖片位置時,圖片才會開始載入,可以顯著減少初始頁面載入時間和頻寬使用。

七種圖片懶加載方法

1. 原生懶加載

HTML Living Standard 定義的 loading 屬性是最簡單的懶加載方式:

1
<img src="image.jpg" loading="lazy" alt="懶加載圖片">

支援度:Chrome 77+、Firefox 75+、Safari 16.4+,全球覆蓋率約 95%。不支援的舊版瀏覽器會忽略此屬性,圖片照常載入,無需額外後備處理。

優點:

  • 零程式碼,無需 JavaScript
  • 瀏覽器原生支援,效能佳

缺點:

  • Safari 16.4 以下(含 iOS 16.4 以下)不支援

2. Intersection Observer API

這是一個強大的 JavaScript API,用於監測元素是否進入視口:

1
2
3
4
5
6
7
8
9
10
11
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const image = entry.target;
image.src = image.dataset.src;
observer.unobserve(image);
}
});
});

document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img));

優點:

  • 高度可自訂
  • 效能優異
  • 可用於其他元素的懶加載

缺點:

  • 需要較多程式碼
  • 部分舊版瀏覽器不支援

3. 滾動事件監聽

傳統但仍有效的方法,適用於不支援 Intersection Observer 的環境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top < (window.innerHeight || document.documentElement.clientHeight) &&
rect.bottom > 0
);
}

function lazyLoad() {
const images = document.querySelectorAll('img[data-src]');
images.forEach((img) => {
if (isInViewport(img)) {
img.src = img.dataset.src;
}
});
}

window.addEventListener('scroll', lazyLoad);
window.addEventListener('load', lazyLoad);

注意:scroll 事件每秒可觸發數百次,生產環境請加上 throttle 或 debounce,否則圖片密集頁面會明顯掉幀。現代瀏覽器優先考慮改用第 2 種 Intersection Observer。

優點:

  • 相容性好,無需現代 API

缺點:

  • 未加 throttle 時會拖慢滾動效能
  • 需要額外函式判斷元素是否在視口內

4. 使用第三方庫

許多成熟的懶加載庫如 lazysizes、lozad.js 等提供了豐富的功能:

1
2
<script src="lazysizes.min.js"></script>
<img data-src="image.jpg" class="lazyload" alt="懶加載圖片">

優點:

  • 功能豐富
  • 相容性好
  • 持續更新和維護

缺點:

  • 增加額外的檔案大小
  • 可能引入不需要的功能

5. 漸進式圖片加載(LQIP)

LQIP(Low Quality Image Placeholder)技術先載入一張體積極小的模糊佔位圖,等高品質圖片下載完成後再切換過去,讓使用者感受到畫面有內容而非空白。

單靠 lazysizes 的基本 data-src 替換並不會產生模糊到清晰的過場效果——那只是延遲載入。要達到真正的漸進式視覺,需要同時引入 ls.blur-up.min.js 外掛,並搭配 CSS 模糊濾鏡:

1
2
3
4
5
6
7
8
<!-- 引入 lazysizes 主體與 blur-up 外掛 -->
<script src="lazysizes.min.js"></script>
<script src="ls.blur-up.min.js"></script>
<img
src="low-quality-tiny.jpg"
data-src="high-quality.jpg"
class="lazyload blur-up"
alt="漸進式加載圖片">
1
2
3
4
5
6
7
.blur-up {
filter: blur(5px);
transition: filter 400ms;
}
.blur-up.lazyloaded {
filter: blur(0);
}

當 lazysizes 將 data-src 載入並加上 lazyloaded class 後,CSS transition 會把模糊效果平滑移除。

優點:

  • 提供模糊到清晰的視覺過場,比突然出現空白體驗更好
  • 適合大圖或需要高清品質的場景

缺點:

  • 需要準備低品質佔位圖(建議壓縮到 1–5 KB)
  • 需要額外的 CSS 與 lazysizes blur-up 外掛,實施比單純懶加載複雜

6. CSS 中的背景圖片懶加載

對於背景圖片,可以用 CSS 加 JavaScript 的組合。HTML 元素需要加上 data-background 屬性,JavaScript 才能讀取目標圖片 URL:

1
<div class="lazy-background" data-background="image.jpg"></div>
1
2
3
4
.lazy-background {
background-image: none;
background-color: #f1f1f1; /* 佔位背景色 */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
document.addEventListener("DOMContentLoaded", function() {
var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

if ("IntersectionObserver" in window) {
let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.style.backgroundImage = "url(" + entry.target.dataset.background + ")";
lazyBackgroundObserver.unobserve(entry.target);
}
});
});

lazyBackgrounds.forEach(function(lazyBackground) {
lazyBackgroundObserver.observe(lazyBackground);
});
}
});

優點:

  • 適用於背景圖片
  • 可以與其他懶加載技術結合

缺點:

  • 實施較為複雜
  • 需要同時修改 HTML、CSS 和 JavaScript

7. Vue.js 中使用 v-if 實現懶加載

在 Vue.js 框架中,可以用 v-if 指令搭配 Intersection Observer API 實現懶加載:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div>
<img v-if="isVisible" :src="imageUrl" :alt="imageAlt">
</div>
</template>

<script>
export default {
props: {
imageUrl: String,
imageAlt: String
},
data() {
return {
isVisible: false
}
},
mounted() {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
this.isVisible = true;
observer.disconnect();
}
});
observer.observe(this.$el);
}
}
</script>

使用方式:

1
2
3
4
5
6
7
8
9
10
<template>
<div>
<lazy-image
v-for="image in images"
:key="image.id"
:image-url="image.url"
:image-alt="image.alt"
/>
</div>
</template>

優點:

  • 與 Vue.js 框架整合自然
  • 可重用性高,易於在不同元件中使用
  • 結合了 Vue 的響應式特性和 Intersection Observer 的效能

缺點:

  • 需要額外的元件封裝
  • 圖片數量多時,建議共用單一 Observer 實例而非每個元件各自建立

這種方法適合 Vue.js 開發的單頁應用(SPA),懶加載邏輯封裝在元件裡,可在整個應用中重複使用。

實施建議

  1. 選擇適合的方法: 根據網站需求和目標使用者群選擇合適的懶加載技術。
  2. 提供後備方案: 確保在不支援懶加載的瀏覽器中也能正常顯示圖片。
  3. 使用現代圖片格式: 考慮使用 WebP 等現代圖片格式,進一步提升載入速度。
  4. 設定圖片尺寸: 為所有圖片設定適當的 widthheight 屬性,避免版面跳動(CLS)。
  5. 注意 SEO: 確保重要圖片能被搜尋引擎正確索引。
  6. 框架整合: 使用 Vue.js、React 或 Angular 時,將懶加載邏輯封裝進元件,提高程式碼可重用性。

    結論

七種方法的選用取捨:新專案優先用原生 loading="lazy",需要精細控制或舊版相容時換 Intersection Observer,只有需要支援極舊瀏覽器才考慮滾動事件版本(記得加 throttle)。背景圖片、LQIP 視覺需求、Vue 元件封裝則按需疊加。