你有沒有遇過這種情況:正準備點一個連結,圖片突然載入,整段文字往下一跳。結果手指點到旁邊的空白,只能在心裡默念:「謝謝,咖啡涼了。」

圖片最佳化不是單純把檔案壓到越小越好。面對 PageSpeed 和 Core Web Vitals,你通常要同時處理兩件事:

  1. LCP(載入速度):首圖什麼時候真正顯示出來?檔案太大、尺寸又不合適,下載自然會變慢。
  2. CLS(版面穩定度):圖片還沒載完之前,下面的內容會不會被往下推?沒有預留寬高,版面就容易跳動。

網站通常有很多圖片,像是產品截圖、比較表和規格圖。這篇先專心處理三件事:控制檔案大小、符合顯示寬度,以及預留圖片版面,並整理成可以直接照做的決策方式和範例。至於 LCP 的 fetchpriority 細節,留到之後再深入討論;這次先把「不要亂跳,也不要浪費頻寬」處理好。

先搞清楚:圖片最常造成兩種效能問題

靜態網站最常見的圖片問題,大概有這幾種:

  • 圖沒有可預測的高度(CLS)
  • hero/內文圖過肥,或丟超大原圖給小螢幕(LCP)
  • 圖很多卻全靠手壓,漏寫 widthheight

這篇會聚焦在:預留圖片尺寸、讓檔案大小和顯示寬度對得上,以及(可選的)Eleventy 圖片處理流程。字體、Cookie 橫幅和第三方腳本造成的 CLS/INP,先留到另一篇處理。一次解決一類問題,才不會改到最後連自己在修什麼都忘了。

以 2026 年的標準來看,Google 建議 CLS ≤ 0.1LCP ≤ 2.5 秒。這裡看的是 CrUX 第 75 百分位的真實使用者資料,不是本機 Lighthouse 跑到 100 分就代表一切沒問題。想先了解 PageSpeed Insights 和欄位資料的差異,可以參考 PageSpeed Insights 與 Core Web Vitals 2026

決策表一:width+height 還是 aspect-ratio?

白話一點說,瀏覽器在下載圖片前,最好先知道「這張圖大概會佔多高」,才不會把下面的內容推歪。HTML 的 widthheight 會提供比例提示;再搭配 max-width: 100%; height: auto;,圖片在響應式縮放時,版面預留仍然有效。

可以把它想成搬家:先用膠帶在地板上標出沙發的位置,就算貨車晚一點到,也不會把其他家具推歪。圖片預留就是那捲膠帶。

情境優先做法為什麼
一般 <img>(hero、內文、產品圖)HTML 真實像素 width + height + CSS max-width:100%; height:auto;web.dev 推薦;瀏覽器自動算比例
比較表/圖牆:多張截圖要同一視覺框外層容器 aspect-ratio: 16/9(或 4/3),圖用 object-fit: cover各圖比例不一也能先佔固定高
iframe/YouTube 等嵌入容器設 aspect-ratio 或固定高度嵌入預設比例常怪,容易抖
還沒定最終檔案尺寸的占位先用 CSS aspect-ratio,上線前補真實寬高過渡方案

一般情況優先使用 HTML 寬高。 CSS 的 aspect-ratio 比較適合容器、嵌入內容或需要統一裁切比例的情境,不能完全取代每張圖片的寬高屬性。

可複製:一般內文/hero

<img
  src="/img/product-dashboard.webp"
  width="1200"
  height="675"
  alt="產品控制台介面截圖"
  decoding="async"
/>
/* 全站圖建議基底——不要寫 width: auto */
img {
  max-width: 100%;
  height: auto;
}

widthheight 要填的是圖片檔案本身的像素尺寸,不是圖片在螢幕上實際顯示的寬度。顯示大小交給 CSS 控制就好。

可複製:固定比例截圖容器

<figure class="shot">
  <img
    src="/img/compare-a.webp"
    width="1600"
    height="900"
    alt="方案 A 設定畫面"
    loading="lazy"
    decoding="async"
  />
</figure>
.shot {
  aspect-ratio: 16 / 9;
  width: 100%;
  overflow: hidden;
  background: #f2f2f2;
}

.shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  max-width: none;
}

常見錯誤(預留會失效)

錯誤為什麼翻車怎麼改
只有 max-width: 100%,沒有 width/height高度從 0 撐開 → 下面全跳補真實 width+height
CSS 寫了 img { width: auto; }蓋掉 HTML 寬度 hint,未載入變 0×0刪掉 width: auto,保留 height: auto
width/height 比例填錯先留錯高,圖載入再校正 → 仍算 CLS用檔案真實像素核對
Lazy 圖沒預留捲到才撐高 → post-load CLSlazy 圖同樣要有寬高

5 分鐘快速檢查:全站搜尋 <img,確認每張圖都有寬高 → 檢查全域 CSS 沒有 width: auto → 用 PSI 或 Performance 面板查看 Layout Shifts。修完再喝一口咖啡,版面和心情都會穩定不少。

決策表二:檔案大小、顯示寬、WebP/AVIF

與其一直調低圖片品質,很多時候先符合顯示寬度更有效。手機上的內容欄可能只有 400px,卻載入一張 4000px 的原圖,像素數量差了不只一點點,下載和解碼都會變慢。這就像點了全家桶外送,最後只吃一塊雞塊。

顯示寬(約)建議產出寬(約,含 2× DPR)
手機全寬 ~360–430px720–860px
內容欄 ~640–720px1280–1440px
Hero 全寬桌面 ~1200px1200–1600px(超過 2000 通常浪費)

站內檔案預算(實務目標,非官方硬門檻)

類型目標大小用法
Hero/LCP 圖< 150KB優先保證首屏最大圖下載快
內文圖/截圖< 80KB長文多圖時累積流量很明顯
小縮圖/圖示< 20–30KB能用 SVG/CSS 就別用照片

這些數字不是 Google 訂下的官方門檻;Google 真正關心的是載入時間和版面位移。把圖片控制在合理大小,是讓使用慢速手機或 4G 網路的讀者更容易通過 LCP 的實用做法。

如果圖片超過預算,可以按照這個順序處理:先縮小寬度 → 改用 AVIF/WebP → 微調壓縮品質 → 裁掉不重要的背景

格式怎麼選

條件建議
靜態站、build 一次產檔AVIF + WebP + JPEG<picture>
只想維護一種現代格式WebP + JPEG
UI 截圖、文字要銳利別壓太狠;必要時略提高品質
Logo/簡單圖示SVG 優先

<picture> 順序:先 AVIF,再 WebP,<img> 用 JPEG/PNG 兜底。瀏覽器會選第一個它吃得下的。

最小可用:srcset + sizes

<img
  src="/img/guide-800.webp"
  srcset="
    /img/guide-400.webp 400w,
    /img/guide-800.webp 800w,
    /img/guide-1200.webp 1200w
  "
  sizes="(max-width: 768px) 100vw, 720px"
  width="1200"
  height="675"
  alt="設定步驟示意"
  loading="lazy"
  decoding="async"
/>

sizes 寫錯,瀏覽器常會下太大檔——等於你說「我只要一杯」,店員卻端來整壺。Hero/LCP 圖請用 loading="eager"(必要時加 fetchpriority="high"),別把首屏主角設成懶載入。

手動壓檔可用 Squoosh:先縮寬 → 試 AVIF/WebP → 符合 KB 預算 → 再寫真實寬高。

決策表三:手動補寬高,還是上 Eleventy 圖片管道?

圖片不多時,手動處理還可以接受;但如果網站每週都要放截圖,漏寫寬高或直接放出原始大圖,幾乎只是早晚的事。尤其是請 AI 產生 Markdown 時,它很愛順手塞一張超肥的 PNG。

如果你使用 Eleventy,可以考慮官方套件 @11ty/eleventy-img。建議先從 Image HTML Transform 開始,它能在建置時自動產生多種尺寸和現代圖片格式,也會幫你補上 widthheight

情境建議
全站 < ~20 張圖、很少更新手動縮圖 + 寫 width/height 可接受
部落格持續貼截圖/heroHTML Transform(推薦)
需要每圖不同裁切/藝術方向Image shortcode 或 WebC
只要先救 CLS、暫不產多尺寸至少手動補真實寬高

最小設定概念:

import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";

export default function (eleventyConfig) {
  eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
    formats: ["avif", "webp", "jpeg"],
    widths: [400, 800, 1200, "auto"],
    htmlOptions: {
      imgAttributes: {
        loading: "lazy",
        decoding: "async",
        sizes: "(max-width: 768px) 100vw, 720px",
      },
    },
  });
}

注意:Transform 預設通常會使用 loading: "lazy"Hero/LCP 圖要改成 eager,必要時再加上 fetchpriority="high"。如果產生了多種寬度,也要記得設定合理的 sizes,否則瀏覽器可能把它當成 100vw,下載比實際需要更大的圖片。

建議按照這個順序導入:先檢查全站圖片並補上寬高,先把 CLS 穩住 → 再開啟 Transform,抽查建置結果 → 新文章只放合理尺寸的原圖。不要再丟一張 8000px 的巨圖,然後安慰自己「以後可能用得到」。

Hugo/Astro 也有對應圖片管道;原則相同:建置時產對的尺寸 + 寫上寬高

推薦工具/資源

需求工具/做法適合誰
手動壓到 KB 目標Squoosh、ImageOptim圖少、先驗流程
Eleventy 自動多尺寸+寬高@11ty/eleventy-img Transform持續發文的靜態站
驗收欄位資料GSC → 體驗 → Core Web Vitals、PageSpeed Insights修完要對真實使用者分數
圖都瘦了但全站仍慢(TTFB/憑證)ZeroSSL 檢查/更新 HTTPS 憑證鏈自架或憑證快到期、混合內容警告時

HTTPS 正常、憑證鏈完整,才不會在傳輸層又多出一個體驗問題。圖片預留和壓縮檔案,主要解決的是前端 CLS 與下載量;HTTPS 憑證則是另一個層次,兩者最好分開檢查。憑證設定可以參考站內的 ZeroSSL 教學

結語:圖片最佳化,就是別讓 CLS 亂跳、也別拖慢下載

  • 每張 <img> 補真實 widthheight(或容器 aspect-ratio);刪掉會搞壞預留的 width: auto
  • 顯示寬符合再壓檔:hero 瞄準 < 150KB、內文 < 80KB;優先 AVIF/WebP
  • 圖一多就上 build 管道(Eleventy 用 eleventy-img),hero 記得覆寫勿 lazy
  • 用 GSC/PSI 驗收;欄位資料大約看 28 天滾動

下一步:先替全站圖片補齊寬高,並檢查 Hero 和內文圖片是否符合檔案預算。如果建置產物都沒問題,但 TTFB 仍然偏高,或憑證出現警告,再用 ZeroSSL 把 HTTPS 和憑證鏈處理好,最後回到 GSC 對照體驗資料。檢查完,再來一杯咖啡。