Hình ảnh thường chiếm 50-70% dung lượng tải trang và là nguyên nhân hàng đầu gây điểm LCP (Largest Contentful Paint) thấp. Trong môi trường production, tối ưu hình ảnh không chỉ là dùng đúng thẻ tag, mà là xây dựng một quy trình phân phối ảnh (Image Delivery Pipeline).
1. Vấn đề của thẻ <img> truyền thống
Sử dụng thẻ <img> thuần túy trong các ứng dụng hiện đại gây ra các vấn đề nghiêm trọng về hiệu năng:
- Cumulative Layout Shift (CLS): Hình ảnh load chậm đẩy nội dung xuống dưới, gây giật lag giao diện.
- Over-fetching: Tải ảnh 4000px cho một khung hiển thị mobile 300px.
- Legacy Formats: Sử dụng JPEG/PNG thay vì các định dạng nén tốt hơn như WebP/AVIF.
2. Giải pháp: Next.js Image Component
Component next/image không chỉ là một wrapper UI, nó hoạt động như một hệ thống tối ưu hóa tự động.
Cơ chế hoạt động:
- On-demand Optimization: Ảnh gốc không được xử lý trước. Khi user request ảnh, Next.js Server (hoặc CDN) mới resize và nén ảnh cached cho lần sau.
- Format Negotiation: Tự động trả về AVIF cho Chrome, WebP cho Firefox, và JPEG cho Safari cũ dựa trên
Acceptheader. - Size Attributes: Bắt buộc khai báo
width/height(hoặcfill) để trình duyệt dự trữ không gian, loại bỏ hoàn toàn CLS.
import Image from 'next/image';
import heroImg from '/public/hero.jpg';
export function Hero() {
return (
<div className="relative h-[500px] w-full">
<Image
src={heroImg}
alt="Hero Banner"
fill
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover"
/>
</div>
);
}3. Chiến lược LCP (Largest Contentful Paint)
LCP là chỉ số đo tốc độ load của phần tử lớn nhất trong viewport. Để đạt điểm xanh (<2.5s), chiến lược tải ảnh cực kỳ quan trọng:
- Priority Loading: Luôn thêm property
prioritycho ảnh LCP (thường là ảnh Hero hoặc ảnh sản phẩm chính). Điều này thêm thẻ<link rel="preload">vào HTML head. - Avoid Lazy Loading LCP: Mặc định
next/imagedùng lazy loading. Điều này TỐT cho ảnh dưới fold, nhưng RẤT TỆ cho ảnh LCP. Luôn tắt lazy load cho ảnh đầu trang. - Fetch Priority: Sử dụng
fetchPriority="high"(Next.js 13.5+) để báo trình duyệt ưu tiên tải hình ảnh này trước cả CSS/JS không quan trọng.
4. Engineering Case Study: E-commerce Listing
Các trang thương mại điện tử lớn (như Amazon, Shopee) đối mặt với thách thức hiển thị hàng nghìn ảnh sản phẩm với tốc độ cuộn nhanh.
Giải pháp "Blur-up Placeholder": Thay vì để khoảng trắng trong khi ảnh đang load, họ sử dụng một phiên bản siêu nhỏ (10px) đã được base64 encode hoặc một chuỗi mã hóa màu (BlurHash).
Implementation trong Next.js:
Sử dụng placeholder="blur" với ảnh import tĩnh, hoặc tự tạo BlurHash cho ảnh động từ API.
// blurDataURL là chuỗi base64 pixel nhỏ của ảnh
<Image
src={product.image}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
{...props}
/>5. Checklist Tối ưu hóa (Production Readiness)
- Format: Cấu hình
next.config.jsđể ưu tiênformats: ['image/avif', 'image/webp']. AVIF nén tốt hơn WebP 20%. - Sizes: Định nghĩa thuộc tính
sizeschính xác. Đừng dùng100vwcho mọi ảnh. Hãy media query chính xác (VD: Mobile 100vw, Tablet 50vw, Desktop 33vw). - CDN: Sử dụng Edge Network (Vercel Blob, Cloudinary, Imgix) để serve ảnh từ server gần người dùng nhất.
Kết luận
Đừng phó mặc hình ảnh cho trình duyệt. Hãy kiểm soát kích thước, định dạng và thứ tự tải của từng bức ảnh để đảm bảo trải nghiệm người dùng nhanh nhất có thể.