0

Image optimization (Phần 2): Next.js Image Component

Giới thiệu

Ở phần trước mình đã nói về Image optimization và cách tối ưu image đối với HTML <img> tag

Khi sử dụng Next.js, nên dùng component Image (mở rộng từ HTML <img> tag) để tự động tối ưu hình ảnh.

Next.js Image component giúp tự động hóa phần lớn quá trình tối ưu image. Tuy nhiên, để đạt hiệu quả tốt nhất, vẫn cần hiểu rõ cách hoạt động của các props và config, cũng như cách browser xử lý image trong thực tế.

Nội dung

1. Một số props quan trọng:

import Image from 'next/image'

export default function Page() {
  return (
    <Image
      src="/image.jpg"
      alt="Example image"
      width={500}
      height={300}
      sizes="(max-width: 768px) 100vw, 400px"
      priority={false}
      loading="lazy"
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,..."
      quality={75}
    />
  )
}

sizes

  • Screen ≤ 768px: image rộng 100vw; > 768px: image rộng 400px
  • Xác định kích thước hiển thị của image theo từng breakpoint
  • Browser sẽ dựa vào sizes để chọn resource phù hợp từ srcset
  • Default là 100vw, nếu không cấu hình đúng, browser có thể tải image lớn hơn cần thiết

width / height

  • Dùng để xác định aspect ratio, giúp browser chừa sẵn không gian và tránh layout shift (CLS)
  • Kích thước hiển thị thực tế vẫn do CSS quyết định
// Hiển thị width: 400px 
<Image
  src="/image.jpg"
  alt="Example image"
  width={500}
  height={300}
  style={{ width: "400px", height: "auto" }}
  sizes="400px"
/>
  • Nếu không xác định được width/height thì dùng fill

    <div
      style={{
        width: "100%",
        height: "300px",
        maxWidth: "800px",
        position: "relative"
      }}
    >
      <Image
        src="/image.jpg"
        alt="Example image"
        fill
        style={{ objectFit: "cover" }}
        sizes="(max-width: 768px) 100vw, 800px"
      />
    </div>
    

priority

  • Dùng cho hero / LCP image để preload và load sớm nhất

loading

  • Default là "lazy”
  • Chỉ dùng "eager" khi không dùng priority nhưng vẫn muốn load sớm

placeholder + blurDataURL

  • Tạo hiệu ứng blur khi image đang load
  • Giúp cải thiện perceived performance (cảm giác load nhanh hơn)
  • Có thể sử dụng thư viện plaiceholder để generate blur data url

quality

  • Giá trị từ 1–100 (default: 75) để điều chỉnh chất lượng ảnh.
  • Giá trị càng cao thì ảnh rõ hơn nhưng dung lượng lớn hơn, càng thấp thì nhẹ hơn nhưng có thể giảm độ sắc nét.

2. Config trong next.config.js

Nếu không cấu hình, Next.js sẽ dùng mặc định:

images: {
  deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840]
  imageSizes: [32, 48, 64, 96, 128, 256, 384],
  formats: ['image/webp'],
  qualities: 75
}
  • deviceSizes : danh sách breakpoint, tạo image lớn (responsive full-width)
  • imageSizes :
    • Tạo image nhỏ (icon, card, avatar,…)
    • Kết hợp với deviceSizes tạo thành danh sách kích thước đầy đủ ([32, 48,…, 384, 640, 750,…., 3840] ) dùng để generate srcset.
  • Các giá trị trong imageSizes phải nhỏ hơn giá trị nhỏ nhất của deviceSizes.

Ngoài ra còn các config này chủ yếu ảnh hưởng đến caching, network và server load. Cấu hình hợp lý theo nhu cầu project giúp tăng cache hit, giảm latency và tránh xử lý lại image không cần thiết.

images: {
  minimumCacheTTL: 14400, // 4 hours
  disableStaticImages: false,
  maximumRedirects: 3,
  maximumDiskCacheSize: 500_000_000, //500 MB
  maximumResponseBody: 50_000_000, //50 MB
}

Trong thực tế, nên giữ gần default và chỉ điều chỉnh khi gặp bottleneck cụ thể (cache miss cao, disk đầy, image quá lớn…)

3. Khi nào không cần optimize image?

Không cần quan tâm optimization đối với: các hình nhỏ (<1KB), SVG, hoặc GIF.

  • Sử dụng unoptimized prop

    <Image {...props} unoptimized />
    
  • Config trong next.config.js (version từ 12.3.0)

    module.exports = {
      images: {
        unoptimized: true,
      },
    }
    

4. Lưu ý các bugs có thể có trên browser (browser compatibility)

  • Lazy loading: browser cũ (trước Safari 15.4) có thể fallback sang eager loading
  • Placeholder: blur placeholder không hỗ trợ trước Safari 12 (fallback về empty)
  • Aspect ratio: browser cũ (trước Safari 15) không giữ aspect ratio, có thể gây layout shift (CLS)

Lời kết

Cảm ơn bạn đã đọc bài viết. Nếu có góp ý, hãy để lại comment để mình có thể cập nhật và cải thiện nội dung.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí