Skip to content

WebP、AVIF 還是 JPEG?圖片格式選擇與降級寫法

圖片格式選擇:WebP、AVIF 與降級寫法

圖片通常是網頁最重的資源,而 換個格式 常是最省力的優化,不必改版面、不必改程式邏輯,同一張圖就少下載一半的位元。

五種格式的比較

格式壓縮效率支援度透明動畫適合
AVIF最好較新照片類大圖
WebP廣泛多數情境的預設
JPEG一般全面降級備援
PNG照片差、圖形好全面需要透明的點陣圖
SVG不適用全面圖示、插圖、線條

三句話的決策規則

不必每次都糾結

  1. 圖示、插圖、線條圖形SVG
  2. 照片與螢幕截圖WebP
  3. 想再壓小、且願意做降級AVIF 加 WebP 備援

SVG:圖示的唯一選擇

html
<img src="/icon-search.svg" alt="搜尋" width="24" height="24">
優點說明
任何解析度都清晰向量圖沒有像素概念
體積小簡單圖示通常只有幾 KB
可用樣式改色內嵌時能用 fillcurrentColor
支援深色模式可以內嵌媒體查詢
不必準備多種尺寸一個檔案通吃

SVG 可以內嵌媒體查詢

html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <style>
    .shape { fill: #0065a9; }
    @media (prefers-color-scheme: dark) {
      .shape { fill: #2b93da; }
    }
  </style>
  <path class="shape" d="..." />
</svg>

這對 favicon 特別有用。

SVG 也需要壓縮

設計工具匯出的 SVG 常含大量無用的中繼資料與過多小數位。用最佳化工具處理過通常能少一半體積。

另外 SVG 是 XML,記得處理特殊字元,檔案裡如果有 <& 這類字元沒轉義,整份 SVG 會變成不合法的 XML,瀏覽器直接放棄渲染。

WebP:照片的預設選擇

多數專案直接全面採用,不做降級

WebP 的支援度已經很廣泛。除非使用者群包含較舊的環境,否則可以直接用它取代 JPEG 與 PNG。

相較於同畫質下的體積
JPEG少約 25-35%
PNG(照片)少非常多
PNG(圖形、需透明)少約 20-25%

WebP 同時支援有損與無損壓縮,也支援透明,所以它能同時取代 JPEG 與 PNG 兩者的角色。

AVIF:追求極致壓縮

相較於同畫質下的體積
WebP再少約 20-30%
JPEG少約 50%

代價有三個

  1. 編碼慢:建置時間會明顯增加,大量圖片時更有感。
  2. 工具鏈支援較晚:部分影像處理套件的支援還不完整。
  3. 仍需降級:部分環境不支援。

值得用的情況:照片類的大圖(主視覺、產品照)。這些圖原本就佔了大部分流量,省 30% 很有感。

不值得的情況:小圖與圖示。一張 5KB 的圖省 30% 只是 1.5KB,不值得多一份檔案與降級邏輯。

用 picture 做降級

<picture> 讓瀏覽器 挑第一個它支援的來源

html
<picture>
  <source srcset="/photo.avif" type="image/avif">
  <source srcset="/photo.webp" type="image/webp">
  <img
    src="/photo.jpg"
    alt="說明文字"
    width="1200"
    height="800"
    loading="lazy"
    decoding="async"
  >
</picture>
規則說明
順序 從新到舊瀏覽器挑第一個支援的,所以壓縮率最好的放最前面
<img>必備它是最後的備援,也承載 alt 與尺寸屬性
屬性寫在 <img>altwidthheightloading 都寫在這裡

順序寫反就沒有效果

html
<!-- 錯誤:支援 AVIF 的瀏覽器也會拿到 WebP -->
<picture>
  <source srcset="/photo.webp" type="image/webp">
  <source srcset="/photo.avif" type="image/avif">
  <img src="/photo.jpg" alt="說明文字">
</picture>

搭配響應式尺寸

<source> 裡也可以放 srcsetsizes

html
<picture>
  <source
    type="image/avif"
    srcset="/photo-400.avif 400w, /photo-800.avif 800w, /photo-1600.avif 1600w"
    sizes="(max-width: 600px) 100vw, 800px"
  >
  <source
    type="image/webp"
    srcset="/photo-400.webp 400w, /photo-800.webp 800w, /photo-1600.webp 1600w"
    sizes="(max-width: 600px) 100vw, 800px"
  >
  <img
    src="/photo-800.jpg"
    alt="說明文字"
    width="800"
    height="600"
    loading="lazy"
  >
</picture>

這樣一張圖要準備九個檔案(三種格式 × 三種尺寸),所以 一定要自動化,寫法見 響應式圖片 srcset 與 sizes

CSS 背景圖的降級

image-set()

css
.hero {
  background-image: image-set(
    url("/hero.avif") type("image/avif"),
    url("/hero.webp") type("image/webp"),
    url("/hero.jpg") type("image/jpeg")
  );
}

背景圖的下載時機比較晚

瀏覽器要先下載並解析 CSS 才會發現這張圖。首屏的主視覺建議改用 <img>,或搭配 preload ,理由見 最大內容繪製 LCP

壓縮品質怎麼設

品質效果
90 以上收益很小,體積卻明顯變大
75 - 85多數人看不出差異,體積少一半以上
70 - 75仔細看得出壓縮痕跡
70 以下明顯劣化

大面積平滑漸層要保守

天空、皮膚、單色背景這類平滑區域最容易出現色塊。這種圖把品質往上調到 85 左右比較安全。

反之,細節豐富的照片(樹葉、紋理)壓到 75 也看不出來。

自動化轉檔

手工轉檔一定會漏

三種格式 × 三種尺寸 = 一張圖九個檔案。手工做不但累,還一定會出現「有新圖但忘了轉格式」的漏洞。

用建置腳本批次處理:

js
import sharp from 'sharp';
import { readdir } from 'node:fs/promises';
import path from 'node:path';

const SIZES = [400, 800, 1600];
const QUALITY = 82;

const files = (await readdir('src/images')).filter((f) => /\.(jpe?g|png)$/i.test(f));

for (const file of files) {
  const base = path.parse(file).name;
  const input = path.join('src/images', file);

  for (const width of SIZES) {
    const pipeline = sharp(input).resize(width);

    await pipeline.clone().webp({ quality: QUALITY }).toFile(`dist/${base}-${width}.webp`);
    await pipeline.clone().avif({ quality: QUALITY }).toFile(`dist/${base}-${width}.avif`);
    await pipeline.clone().jpeg({ quality: QUALITY }).toFile(`dist/${base}-${width}.jpg`);
  }
}

框架通常有現成的圖片元件

Nuxt、Next 這類框架都有內建的圖片處理,會自動產生多種格式與尺寸並輸出正確的 <picture>。自己寫腳本前先確認框架有沒有提供。

社群分享的圖片要用 PNG 或 JPEG

部分社群爬蟲不支援 WebP 與 SVG

Open GraphTwitter Card 的圖片如果用 WebP 或 SVG,部分平台的預覽卡片會 沒有圖

站內顯示用現代格式,社群分享另外準備一份 1200 × 630 的 PNG 或 JPEG。

這個站的做法

用途格式理由
文章橫幅SVG-banner.svg純圖形與文字,向量最合適,只有幾 KB
社群分享圖PNG-og.png社群爬蟲的相容性
網站標誌與 faviconSVG任何尺寸都清晰,可支援深色模式
螢幕截圖與照片WebP照片類的預設選擇

橫幅是用腳本產生的 SVG,og 圖則由另一支腳本從橫幅轉出:

bash
# 產生所有橫幅 SVG
npm run seo:banners

# 掃過所有 *-banner.svg,包成 1200×630 的 og:image PNG
npm run og:images

一個來源產生兩種輸出

新增文章時只要在腳本的清單裡加一筆,橫幅與社群圖都自動跟上,不會出現「有文章卻沒有 og 圖」的漏洞。

因為 SVG 是文字檔,這個站所有橫幅加起來也才幾百 KB,還能進版本控制看 diff。

檢查清單

項目標準
圖示與插圖用 SVG建議
照片用 WebP 或 AVIF建議
<picture><source> 順序從新到舊必備
<picture> 內有 <img> 當備援必備
alt 與尺寸寫在 <img>必備
壓縮品質在 75-85建議
SVG 已經過最佳化處理建議
社群分享圖是 PNG 或 JPEG必備
轉檔由建置流程自動處理建議

常見問題

只用 WebP 可以嗎?

可以。它的支援度已經很廣泛,多數專案直接全面採用而不做降級。真正需要降級的是使用者群包含較舊環境的網站,或需要用 AVIF 追求極致壓縮的情況。

AVIF 值得用嗎?

照片類的大圖值得。它的壓縮率明顯優於 WebP,同畫質下常再少三成體積。代價是編碼較慢、工具鏈支援較晚,而且部分環境仍不支援所以需要降級。小圖的效益不明顯。

圖示該用什麼格式?

SVG。它是向量的,任何解析度都清晰,體積通常只有幾 KB,還能用樣式改色與支援深色模式。點陣格式的圖示在高解析度螢幕上會模糊,也需要準備多種尺寸。

壓縮品質設多少?

照片類設在 75 到 85 之間,多數人看不出與原圖的差異,體積卻能少一半以上。超過 90 的收益很小,低於 70 開始出現明顯的壓縮痕跡。有大面積平滑漸層的圖要保守一些。

社群分享的圖片可以用 WebP 嗎?

不建議。部分社群平台的預覽爬蟲不支援 WebP 與 SVG,卡片就會沒有圖。社群分享用的圖片一律準備 PNG 或 JPEG,站內顯示才用現代格式。

延伸閱讀

參考資料:web.dev:Image formats