Ảnh chiếm phần lớn trọng lượng trang web — HTTP Archive 2025 ghi nhận trung bình ~900 KB ảnh trên trang desktop top site. Format chọn sai → LCP rơi, user rời sớm, SEO mất điểm. Bài này giúp bạn chọn format đúng (PNG, JPEG, WebP, AVIF, SVG) và triển khai responsive gọn trong HTML/CSS.


1. Bốn loại nội dung ảnh — chọn format khác nhau

Trước khi bàn “PNG hay AVIF”, xếp ảnh vào 4 nhóm:

  1. Ảnh chụp / photo / illustration liên tục tông màu → JPEG / WebP lossy / AVIF.
  2. Ảnh đồ hoạ / UI / screenshot / logo có viền sắc → PNG / WebP lossless / AVIF (với mode lossless nếu cần).
  3. Vector (logo, icon) → SVG (độ phân giải độc lập, file nhỏ).
  4. Trong suốt (transparency) → PNG / WebP / AVIF (JPEG không có alpha).

Dưới đây đi sâu từng format.


2. Profile từng format

2.1. PNG (lossless)

  • Không mất chất lượng; có alpha (trong suốt).
  • To, đặc biệt với ảnh photo.
  • Hợp: screenshot, UI, logo đơn giản cần pixel chính xác.

Tối ưu: pngquant, oxipng, zopflipng — giảm 30–70% file mà không thay đổi pixel (hoặc có tuỳ pngquant).

2.2. JPEG (lossy)

  • Tiêu chuẩn hơn 30 năm; support mọi nơi.
  • Không có alpha.
  • Progressive JPEG cho phép hiển thị ảnh mờ trước khi load xong → UX tốt hơn baseline.
  • Chất lượng quality=75–82 thường là sweet spot; sub-sampling 4:2:0 cho ảnh photo; 4:4:4 cho ảnh có chi tiết màu sắc quan trọng (text đỏ trên xanh).

Tool: mozjpeg (libjpeg fork) — encode chặt hơn ~10–15% so với libjpeg-turbo ở cùng chất lượng nhìn.

2.3. WebP

  • Google 2010; hỗ trợ lossy lossless, alpha, animation.
  • Thường nhỏ hơn JPEG ~25–35% ở cùng chất lượng cảm quan.
  • Hỗ trợ trình duyệt: ~97% (tất cả trình duyệt hiện đại, Safari từ 2020).
  • Fallback JPEG/PNG cho IE11 — nếu bạn còn phải hỗ trợ.

Tool: cwebp, sharp, ImageMagick.

2.4. AVIF (AV1 Image File Format)

  • Kế thừa codec AV1 (video); ra mắt ~2019.
  • Nén tốt hơn WebP 20–50%, hỗ trợ HDR, 10/12-bit, alpha.
  • Support: Chrome, Edge, Firefox, Safari 16+ (~90% globally, 2025).
  • Encode chậm hơn nhiều so với WebP/JPEG — cần cân nhắc build pipeline.
  • Đôi khi artifact ở ảnh có chi tiết nhỏ (text) — test bằng mắt thật.

Tool: avifenc (libavif), sharp (Node), ImageMagick 7.

2.5. SVG

  • Vector, XML-based. Scale vô hạn.
  • Phù hợp: logo, icon, illustration phẳng.
  • Nhớ: minify (SVGO) và inline cho các icon nhỏ (giảm request).
  • Cẩn trọng XSS nếu user upload SVG — strip <script>, external refs.

3. Quyết định nhanh

Trường hợpChọn
Ảnh banner/hero, photoAVIF + WebP + JPEG fallback
Thumbnail photoWebP + JPEG fallback
Screenshot UI, diagramPNG (qua oxipng) hoặc WebP lossless
Logo / iconSVG (inline nếu nhỏ)
AnimatedWebP animation hoặc AVIF (video H.264/AV1 cho GIF dài)

Không dùng GIF cho animation lớn — file nặng, chất lượng tệ. Thay bằng video <video> (MP4/WebM) hoặc WebP animation.


4. Responsive images với <picture>srcset

4.1. <picture> — fallback theo format

Trình duyệt duyệt từ trên xuống, dùng <source> đầu tiên hỗ trợ:

<picture>
  <source type="image/avif" srcset="/img/hero.avif" />
  <source type="image/webp" srcset="/img/hero.webp" />
  <img
    src="/img/hero.jpg"
    alt="Hero"
    width="1600"
    height="900"
    loading="lazy"
  />
</picture>

Tối thiểu luôn có <img> fallback. Đặt width/height thực tế để tránh CLS (Cumulative Layout Shift).

4.2. srcset + sizes — chọn resolution theo viewport

<img
  src="/img/hero-800.jpg"
  srcset="
    /img/hero-400.jpg   400w,
    /img/hero-800.jpg   800w,
    /img/hero-1600.jpg 1600w
  "
  sizes="(min-width: 1024px) 50vw, 100vw"
  alt="Hero"
  width="1600"
  height="900"
  loading="lazy"
/>
  • srcset liệt kê các phiên bản theo width.
  • sizes nói cho trình duyệt biết kích thước hiển thị thực tế ở mỗi breakpoint.
  • Trình duyệt chọn ảnh vừa đủ phân giải — không tải ảnh 1600w xuống điện thoại 400w.

Kết hợp cả hai:

<picture>
  <source
    type="image/avif"
    srcset="
      /img/hero-400.avif   400w,
      /img/hero-800.avif   800w,
      /img/hero-1600.avif 1600w
    "
    sizes="(min-width: 1024px) 50vw, 100vw"
  />
  <source
    type="image/webp"
    srcset="
      /img/hero-400.webp   400w,
      /img/hero-800.webp   800w,
      /img/hero-1600.webp 1600w
    "
    sizes="(min-width: 1024px) 50vw, 100vw"
  />
  <img
    src="/img/hero-800.jpg"
    srcset="
      /img/hero-400.jpg   400w,
      /img/hero-800.jpg   800w,
      /img/hero-1600.jpg 1600w
    "
    sizes="(min-width: 1024px) 50vw, 100vw"
    alt="Hero"
    width="1600"
    height="900"
    loading="lazy"
  />
</picture>

5. Lazy loading và fetch priority

5.1. loading="lazy"

Trì hoãn tải ảnh ngoài viewport — tiết kiệm băng thông, tăng tốc render. Không đặt lazy cho ảnh above-the-fold (hero, LCP) — sẽ trì hoãn LCP.

5.2. fetchpriority

<img src="/img/hero.jpg" fetchpriority="high" ... />

Nói với trình duyệt ưu tiên tải ảnh này. Thường dùng cho ảnh LCP.

5.3. decoding

<img decoding="async" ... />

Báo trình duyệt được decode off-main-thread; giảm long task. Thường async là an toàn.

5.4. Preload cho LCP

<link
  rel="preload"
  as="image"
  imagesrcset="/img/hero-800.avif 800w, /img/hero-1600.avif 1600w"
  imagesizes="(min-width: 1024px) 50vw, 100vw"
  type="image/avif"
/>

Preload chỉ cho ảnh chắc chắn sẽ dùng (LCP). Preload bừa → tốn băng thông.


6. Pipeline build

6.1. Dùng CDN ảnh

Cloudflare Images, imgix, Cloudinary, Akamai Image Manager… nhận URL, trả về ảnh tự động chọn format theo Accept header.

/cdn/hero.jpg?w=800&q=75

Không phải dự án nào cũng cần, nhưng cho site có nhiều ảnh user upload thì đỡ vô vàn việc.

6.2. Self-host với sharp (Node)

import sharp from "sharp";

async function build(input, outDir) {
  const sizes = [400, 800, 1600];
  for (const w of sizes) {
    await sharp(input)
      .resize({ width: w })
      .jpeg({ quality: 78, mozjpeg: true })
      .toFile(`${outDir}/hero-${w}.jpg`);
    await sharp(input)
      .resize({ width: w })
      .webp({ quality: 78 })
      .toFile(`${outDir}/hero-${w}.webp`);
    await sharp(input)
      .resize({ width: w })
      .avif({ quality: 50 })
      .toFile(`${outDir}/hero-${w}.avif`);
  }
}

Chạy trong build-time (Next, Nuxt, Astro, Hugo pipes) → caching hiệu quả, không encode khi request.

6.3. Chi phí CPU encode

AVIF encode có thể chậm 10–50 lần JPEG. Nếu bạn có nhiều ảnh user upload real-time, encode AVIF async (push job queue, serve JPEG/WebP trước, thay ảnh khi AVIF xong) hoặc dùng CDN.


7. Đo ảnh hưởng đến CWV

  • LCP: thường là ảnh hero → tối ưu format + preload + fetchpriority=high → giảm đáng kể.
  • CLS: luôn có width/height (hoặc aspect-ratio CSS) trên ảnh để browser reserve slot.
  • INP: decode ảnh lớn trên main thread có thể gây long task → dùng decoding=async.

Kiểm tra với Lighthouse, PageSpeed Insights (trường data lẫn lab), WebPageTest filmstrip xem chuỗi load.


8. Cạm bẫy thường gặp

8.1. Serve ảnh gốc 4000×3000 cho thumbnail 200×200

Browser resize xuống, nhưng bạn đã trả vài MB thay vì vài KB. Pipeline phải sinh nhiều kích thước.

8.2. Đặt loading=lazy cho ảnh LCP

Gây regression LCP 500–1500ms trên mạng chậm. Luôn đánh dấu LCP bằng eager (mặc định).

8.3. Không tính alpha khi chuyển JPEG → WebP/AVIF lossy

Một số tool convert sẽ fill nền đen/trắng. Kiểm tra output — đặc biệt nếu source có transparency.

8.4. Dùng AVIF cho text-heavy screenshot

Ở quality thấp, AVIF nhoè text tệ hơn WebP lossless hay PNG. Test bằng mắt trước khi đổi toàn bộ.

8.5. Quên cache-control dài hạn

Ảnh đã versioned trong URL (hero-abc123.jpg) → Cache-Control: public, max-age=31536000, immutable. Nếu dùng URL chung, set hợp lý để CDN/browser tận dụng.


9. Tối ưu ảnh cho social share

Open Graph, Twitter Card: thường JPEG 1200×630, không nên AVIF — nhiều social crawler chưa hỗ trợ. Serve JPEG/PNG qua URL riêng cho og:image.


10. Tóm tắt

  • Phân loại ảnh trước, chọn format sau. SVG cho vector, PNG cho UI/screenshot, WebP/AVIF cho photo, JPEG làm fallback.
  • Triển khai <picture> + srcset/sizes thay vì chỉ một <img src>.
  • Width/height hoặc aspect-ratiobắt buộc để tránh CLS.
  • Lazy-load ảnh ngoài viewport; preload + fetchpriority=high cho LCP.
  • Build-time encode với sharp, hoặc dùng CDN ảnh.
  • Đo CWV trước và sau để xác nhận thay đổi có lợi.

Ảnh tốt không chỉ là “chọn AVIF”. Quan trọng là pipeline tự động sinh đúng size + format, HTML khai báo đầy đủ, và ưu tiên phù hợp giữa ảnh LCP và ảnh phụ. Nhỡ có một thứ ở trên sai, toàn bộ công sức tối ưu cũng rơi đáng kể.