LCP 最大內容繪製:找出關鍵元素並壓進 2.5 秒
LCP(Largest Contentful Paint,最大內容繪製)回答使用者最直接的疑問:「主要內容什麼時候看得到?」
| 評級 | 門檻 |
|---|---|
| 良好 | ≤ 2.5 秒 |
| 待改善 | 2.5 - 4.0 秒 |
| 不佳 | > 4.0 秒 |
這是 三個核心指標 中影響第一印象最大的一個。
LCP 元素怎麼判定
它是 可視範圍內面積最大的內容元素。候選只有這幾種:
| 候選 | 說明 |
|---|---|
<img> | 最常見的 LCP 元素 |
<image>(SVG 內) | 向量圖裡的圖片 |
<video> 的封面圖 | poster 屬性指定的那張 |
有 background-image 的元素 | 用樣式載入的背景圖 |
| 包含文字的區塊元素 | 段落、標題、清單 |
LCP 元素會在載入過程中變動
一開始可能是標題文字(因為圖片還沒下載),圖片載入後就變成那張圖。
最終值取的是「使用者第一次互動之前」的最後一個。 所以優化的對象是那個最後勝出的元素。
怎麼找出它
| 工具 | 怎麼看 |
|---|---|
| Lighthouse | 效能報告的「Largest Contentful Paint element」欄位 |
| Chrome DevTools 的 Performance | 時間軸上的 LCP 標記,點下去會高亮那個元素 |
PerformanceObserver | 自己埋設,見 指標量測 |
// 直接在主控台印出 LCP 元素
new PerformanceObserver((list) => {
const entries = list.getEntries();
const last = entries[entries.length - 1];
console.log('LCP:', last.startTime, last.element);
}).observe({ type: 'largest-contentful-paint', buffered: true });把時間拆成四段找瓶頸
不要籠統地說「LCP 太慢」。把它拆開,才知道要修哪裡:
| 階段 | 從哪到哪 | 慢的原因 |
|---|---|---|
| 1. TTFB | 請求發出到收到第一個位元組 | 伺服器慢、沒有 CDN、沒有快取 |
| 2. 資源載入延遲 | TTFB 到開始下載 LCP 資源 | 太晚被發現、優先權太低 |
| 3. 資源載入時間 | 下載 LCP 資源本身 | 檔案太大、格式沒最佳化 |
| 4. 元素繪製延遲 | 下載完到繪製到畫面上 | 阻塞渲染的樣式或程式碼、字型未載入 |
第 2 段最常被忽略
一張圖只要 200 毫秒就能下載完(第 3 段很短),卻在頁面開始載入後 1.5 秒才開始下載(第 2 段很長),這種情況非常常見。
原因通常是:圖片被 loading="lazy" 延遲、藏在 CSS 的背景圖裡(要等樣式解析完)、或由 JavaScript 動態插入。
三個最有效的手法
1. 首屏圖片不要延遲載入,並提高優先權
這是最常見也最嚴重的錯誤
<!-- 錯誤:主視覺被延遲載入 -->
<img src="/hero.webp" alt="主視覺" loading="lazy">延遲載入的圖片要等瀏覽器判斷它接近可視範圍才開始下載,那道判斷本身就是第 2 段的延遲。
<!-- 正確:提高優先權,不延遲 -->
<img
src="/hero.webp"
alt="主視覺"
width="1200"
height="400"
fetchpriority="high"
>| 屬性 | 作用 |
|---|---|
fetchpriority="high" | 告訴瀏覽器這張圖優先下載 |
不寫 loading | 預設就是立即載入 |
width 與 height | 預留空間,避免 CLS |
不寫 decoding | async 的語意是讓其他內容先呈現,首屏圖片留預設 |
整站只有一到兩張圖該設 fetchpriority="high"
它是相對的優先權。全部設成 high 等於沒設,詳見 資源提示 。
其他非首屏的圖片則反過來加 loading="lazy",判斷方式見 圖片延遲載入 。
2. 縮小 LCP 資源的體積
第 3 段的優化就是純粹的檔案大小問題:
| 手法 | 效果 |
|---|---|
| 轉成 WebP 或 AVIF | 同畫質下體積少 25-50% |
| 提供 響應式尺寸 | 手機不下載桌機的大圖 |
| 調整壓縮品質 | 品質 80 通常看不出差異 |
| 圖示改用 SVG | 向量圖通常更小且無限清晰 |
格式選擇見 圖片格式 WebP 與 AVIF 。
3. 移除阻塞渲染的資源
第 4 段的主因。即使圖片已經下載完,只要 CSS 還沒解析完,瀏覽器就不會繪製任何東西。
<!-- 阻塞渲染:要等它下載並解析完 -->
<link rel="stylesheet" href="/styles.css">
<!-- 首屏樣式內嵌,其餘非同步載入 -->
<style>
/* 只放首屏需要的樣式 */
.hero { height: 400px; }
</style>
<link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">程式碼則用 defer 或 async:
<script src="/app.js" defer></script>完整做法見 阻塞渲染的 CSS 與 JavaScript 。
背景圖是隱形的陷阱
CSS 背景圖比 img 晚很多才開始下載
.hero {
background-image: url("/hero.webp");
}瀏覽器必須先下載 CSS、解析它、算出 .hero 這個選取器有匹配到元素,才會開始下載那張圖。這條路徑比 HTML 裡的 <img> 長得多。
三種解法:
<!-- 解法一:改用 img(最推薦) -->
<img src="/hero.webp" alt="主視覺" fetchpriority="high" class="hero-img"><!-- 解法二:保留背景圖,但用 preload 提早開始下載 -->
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">/* 解法三:用 image-set 讓瀏覽器挑格式,仍需搭配 preload */
.hero {
background-image: image-set(url("/hero.avif") type("image/avif"), url("/hero.webp") type("image/webp"));
}文字當 LCP 元素時
如果最大元素是文字(沒有大圖的頁面很常見),重點完全轉向 字型:
文字要等網頁字型載入完才繪製
中文字型動輒數 MB。若 font-display 沒設好,文字會一直不顯示(FOIT),LCP 就等於字型的載入時間。
@font-face {
font-family: "MyFont";
src: url("/fonts/myfont.woff2") format("woff2");
font-display: swap; /* 立刻用備援字型顯示,載完再換 */
}| 手法 | 見 |
|---|---|
font-display: swap | 字型顯示 font-display |
| 子集化縮小體積 | 中文字型子集化 |
| 預載首屏字型 | 資源提示 |
| 直接用系統字型 | 網頁字型與 SEO |
縮短 TTFB
第 1 段的優化屬於後端與部署範圍:
| 手法 | 說明 |
|---|---|
| 用 CDN | 讓資源從離使用者近的節點送出 |
| 設定快取標頭 | 重複造訪直接用快取 |
| 改用 靜態產生 | 不必每次請求都組裝 HTML |
| 資料庫查詢最佳化 | 減少伺服器處理時間 |
細節見 伺服器回應 TTFB 與 FCP 。
排查流程
按這個順序做,通常前兩步就解決:
- 找出 LCP 元素:用 Lighthouse 或上面的
PerformanceObserver。 - 確認它有沒有被延遲載入:搜尋
loading="lazy",如果是 LCP 元素就拿掉並加上fetchpriority="high"。 - 看它是不是背景圖:是的話改用
<img>或加preload。 - 看檔案大小:超過 200KB 就考慮換格式或降品質。
- 拆四段找瓶頸:到這一步還沒解決,就用 DevTools 的 Performance 面板逐段看。
- 用真實數據驗收:見 指標量測與 CrUX 數據 。
這個站的做法
每篇文章的橫幅圖是 LCP 元素,所以它的標記是:
{ width=1200 height=400 fetchpriority="high" }| 決定 | 理由 |
|---|---|
| 用 SVG | 向量圖體積小(幾 KB),任何解析度都清晰 |
標上 width 與 height | 預留空間,避免版面跳動 |
fetchpriority="high" | 它是首屏最大元素 |
不加 loading="lazy" | 首屏圖片絕不延遲 |
不設 decoding | async 會讓其他內容先呈現,首屏圖片留預設 |
文章中段的圖則相反,加 loading="lazy",不設優先權。
檢查清單
| 項目 | 標準 |
|---|---|
| LCP 在 2.5 秒內(第 75 百分位) | 目標 |
首屏圖片沒有 loading="lazy" | 必備 |
首屏圖片有 fetchpriority="high" | 建議 |
首屏圖片有 width 與 height | 必備 |
| LCP 圖片用現代格式 | 建議 |
LCP 不是 CSS 背景圖(或已 preload) | 建議 |
字型有 font-display: swap | 建議 |
| 阻塞渲染的資源已處理 | 建議 |
只有一到兩個資源設 fetchpriority="high" | 必備 |
常見問題
LCP 元素是哪一個?
可視範圍內面積最大的內容元素,候選包含圖片、影片的封面圖、有背景圖的區塊,以及包含文字的區塊元素。它會在載入過程中變動,最終值取的是使用者第一次互動之前的最後一個。
為什麼首屏圖片不能延遲載入?
延遲載入的圖片要等瀏覽器判斷它接近可視範圍才開始下載,這道判斷本身就是延遲。如果那張圖正好是最大內容元素,這個指標會直接變差。首屏圖片應該反過來用 fetchpriority="high" 提高優先權。
改善這個指標最有效的三件事是什麼?
首屏圖片不要延遲載入並提高它的優先權、把圖片轉成 現代格式 縮小體積、以及移除 阻塞渲染的樣式與程式碼 。這三件的成本都不高,通常能解決大部分問題。
文字當作最大內容元素也要優化嗎?
要,而且重點在字型。文字要等網頁字型載入完才繪製,所以字型的體積與載入策略直接決定這個指標。中文字型動輒數 MB,這種情況特別明顯,做法見 網頁字型與 SEO 。
本機測起來很快,為什麼線上數據不佳?
本機沒有真實的網路延遲,裝置也通常比使用者的手機好。真實數據取的是第 75 百分位,涵蓋了中低階裝置與行動網路。除錯用本機工具,驗收要看 真實使用者數據 。