WebP、AVIF 還是 JPEG?圖片格式選擇與降級寫法
圖片通常是網頁最重的資源,而 換個格式 常是最省力的優化,不必改版面、不必改程式邏輯,同一張圖就少下載一半的位元。
五種格式的比較
| 格式 | 壓縮效率 | 支援度 | 透明 | 動畫 | 適合 |
|---|---|---|---|---|---|
| AVIF | 最好 | 較新 | 是 | 是 | 照片類大圖 |
| WebP | 好 | 廣泛 | 是 | 是 | 多數情境的預設 |
| JPEG | 一般 | 全面 | 否 | 否 | 降級備援 |
| PNG | 照片差、圖形好 | 全面 | 是 | 否 | 需要透明的點陣圖 |
| SVG | 不適用 | 全面 | 是 | 是 | 圖示、插圖、線條 |
三句話的決策規則
不必每次都糾結
- 圖示、插圖、線條圖形 → SVG
- 照片與螢幕截圖 → WebP
- 想再壓小、且願意做降級 → AVIF 加 WebP 備援
SVG:圖示的唯一選擇
<img src="/icon-search.svg" alt="搜尋" width="24" height="24">| 優點 | 說明 |
|---|---|
| 任何解析度都清晰 | 向量圖沒有像素概念 |
| 體積小 | 簡單圖示通常只有幾 KB |
| 可用樣式改色 | 內嵌時能用 fill 與 currentColor |
| 支援深色模式 | 可以內嵌媒體查詢 |
| 不必準備多種尺寸 | 一個檔案通吃 |
SVG 可以內嵌媒體查詢
<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% |
代價有三個
- 編碼慢:建置時間會明顯增加,大量圖片時更有感。
- 工具鏈支援較晚:部分影像處理套件的支援還不完整。
- 仍需降級:部分環境不支援。
值得用的情況:照片類的大圖(主視覺、產品照)。這些圖原本就佔了大部分流量,省 30% 很有感。
不值得的情況:小圖與圖示。一張 5KB 的圖省 30% 只是 1.5KB,不值得多一份檔案與降級邏輯。
用 picture 做降級
<picture> 讓瀏覽器 挑第一個它支援的來源:
<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> 上 | alt、width、height、loading 都寫在這裡 |
順序寫反就沒有效果
<!-- 錯誤:支援 AVIF 的瀏覽器也會拿到 WebP -->
<picture>
<source srcset="/photo.webp" type="image/webp">
<source srcset="/photo.avif" type="image/avif">
<img src="/photo.jpg" alt="說明文字">
</picture>搭配響應式尺寸
<source> 裡也可以放 srcset 與 sizes:
<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():
.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 也看不出來。
自動化轉檔
手工轉檔一定會漏
三種格式 × 三種尺寸 = 一張圖九個檔案。手工做不但累,還一定會出現「有新圖但忘了轉格式」的漏洞。
用建置腳本批次處理:
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 Graph 與 Twitter Card 的圖片如果用 WebP 或 SVG,部分平台的預覽卡片會 沒有圖。
站內顯示用現代格式,社群分享另外準備一份 1200 × 630 的 PNG 或 JPEG。
這個站的做法
| 用途 | 格式 | 理由 |
|---|---|---|
| 文章橫幅 | SVG(-banner.svg) | 純圖形與文字,向量最合適,只有幾 KB |
| 社群分享圖 | PNG(-og.png) | 社群爬蟲的相容性 |
| 網站標誌與 favicon | SVG | 任何尺寸都清晰,可支援深色模式 |
| 螢幕截圖與照片 | WebP | 照片類的預設選擇 |
橫幅是用腳本產生的 SVG,og 圖則由另一支腳本從橫幅轉出:
# 產生所有橫幅 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,站內顯示才用現代格式。