Tối ưu ảnh LCP: mức ưu tiên và định dạng
Khi một trang hiển thị nội dung chính chậm, thủ phạm rất thường là một ảnh hero. Nén nó mạnh tay hơn có ích, nhưng hiếm khi là đòn bẩy lớn nhất. Largest Contentful Paint (LCP) là một dòng thời gian gồm nhiều giai đoạn riêng biệt, và định dạng ảnh chỉ là một trong số đó. Bài viết này chia nhỏ dòng thời gian ấy và đưa ra một danh sách ngắn các thay đổi cần làm, theo thứ tự chúng tôi sẽ thử.
Bốn giai đoạn của LCP
web.dev mô tả LCP là bốn phần nối tiếp nhau, cộng lại không có khoảng hở:
- Time to first byte: cho đến khi phần HTML đầu tiên đến nơi.
- Resource load delay: khoảng chờ giữa byte đầu tiên đó và thời điểm trình duyệt bắt đầu tải tài nguyên LCP.
- Resource load duration: quá trình tải xuống mất bao lâu.
- Element render delay: thời gian từ lúc tải xong đến lúc phần tử xuất hiện.
Trên một trang được tinh chỉnh tốt, hướng dẫn gợi ý khoảng 40 phần trăm dành cho TTFB, 40 phần trăm cho việc tải xuống, và mỗi giai đoạn trong hai giai đoạn delay dưới 10 phần trăm. Hướng dẫn nói rõ rằng các tỷ lệ này là gợi ý về sự cân bằng tương đối, không phải mục tiêu cố định. Dù vậy, bài học vẫn hữu ích: các giai đoạn delay nên gần bằng không, nên nếu bạn thấy một khoảng trống lớn trước khi ảnh bắt đầu tải, việc giảm dung lượng tệp bao nhiêu cũng không sửa được. Ngưỡng tốt của chỉ số này là 2,5 giây trở xuống, và mọi giá trị trên 4,0 giây được coi là kém.
Bước 1: để ảnh có thể được phát hiện
Trình duyệt quét HTML thô từ sớm để tìm các tài nguyên đáng tải. Nếu ảnh hero của bạn chỉ xuất hiện sau khi JavaScript chạy, nằm trong thuộc tính data-src chờ một script lazy-loading, hoặc là CSS background, thì lần quét sớm đó không thấy được nó và request bắt đầu muộn. Bài tổng hợp Core Web Vitals trên web.dev trích dữ liệu Web Almanac cho thấy 35 phần trăm ảnh LCP có URL không thể phát hiện trong HTML ban đầu, và khoảng 7 phần trăm bị giấu sau data-src.
<!-- Easy for the preload scanner to find -->
<img src="/img/hero-1200.avif"
width="1200" height="600"
alt="Autumn collection on a wooden table">
Nếu chỉ có stylesheet hoặc script tham chiếu đến ảnh, hãy thêm một preload link cho nó, và đặt mức ưu tiên cao.
Bước 2: nâng mức ưu tiên, và đừng bao giờ lazy-load nó
Hình ảnh không chặn render và không tự động được ưu tiên hàng đầu, nên một gợi ý sẽ có ích. Hãy đặt fetchpriority="high" lên đúng một ảnh mà bạn kỳ vọng là phần tử LCP. Dùng tiết kiệm: đánh dấu nhiều ảnh là ưu tiên cao sẽ làm loãng hiệu quả. Điều ngược lại áp dụng cho các ảnh ban đầu nằm ngoài màn hình, như các slide carousel bị ẩn, nơi fetchpriority="low" giải phóng băng thông.
Sai lầm kinh điển là để nguyên loading="lazy" trên ảnh hero. Lazy loading khiến trình duyệt chờ đến khi layout xác nhận ảnh nằm trong vùng nhìn thấy, tức là thêm đúng độ trễ tải mà bạn đang cố loại bỏ. Theo cùng các nguồn đó, chỉ một tỷ lệ nhỏ các trang đủ điều kiện có dùng fetchpriority, nên đây là cải thiện dễ làm ở nhiều site.
<img src="/img/hero-1200.avif"
fetchpriority="high"
width="1200" height="600"
alt="Autumn collection on a wooden table">
<img src="/img/below-fold.avif"
loading="lazy"
width="600" height="400"
alt="Detail of stitching">
Bước 3: chọn đúng định dạng và kích thước
Khi request đã bắt đầu đúng lúc, thời gian tải xuống phụ thuộc vào số byte. Hướng dẫn về định dạng của web.dev khá đơn giản:
- Dùng SVG cho logo, icon và hình học đơn giản.
- Với ảnh chụp và ảnh chụp màn hình, AVIF hoặc WebP nén có mất dữ liệu (lossy) thường nén tốt hơn JPEG, với JPEG là phương án dự phòng phổ quát.
- Dành PNG hoặc WebP lossless cho những ảnh cần độ trung thực tối đa, và dùng tiết kiệm vì tệp lớn.
- Với hoạt ảnh, phần tử video thường nhẹ hơn GIF hoặc APNG.
Cung cấp các định dạng hiện đại kèm phương án dự phòng chỉ mất vài dòng:
<picture>
<source type="image/avif" srcset="/img/hero-800.avif 800w, /img/hero-1600.avif 1600w" sizes="100vw">
<source type="image/webp" srcset="/img/hero-800.webp 800w, /img/hero-1600.webp 1600w" sizes="100vw">
<img src="/img/hero-1600.jpg" width="1600" height="800" fetchpriority="high" alt="...">
</picture>
Hãy nhớ rằng kích thước quan trọng không kém định dạng. Ví dụ minh họa trong cùng hướng dẫn cho thấy tăng gấp đôi mật độ điểm ảnh làm số điểm ảnh tăng gấp bốn, nên phục vụ ảnh 3x cho màn hình chỉ cần 1x làm khối lượng công việc tăng lên rất nhiều. srcset và sizes responsive cho phép trình duyệt tự chọn, còn các thuộc tính width và height tường minh giữ chỗ để layout không bị nhảy.
Bước 4: kiểm tra server và origin
Vì TTFB là một giai đoạn đầy đủ của dòng thời gian, phản hồi đầu tiên chậm sẽ ăn vào ngân sách trước khi bất kỳ logic ảnh nào có ý nghĩa. Bài tổng hợp đó cũng lưu ý chỉ 33 phần trăm các request HTML trong Web Almanac được phục vụ qua CDN, và gợi ý cache HTML tĩnh, dù chỉ trong thời gian ngắn. Đặt ảnh quan trọng trên cùng origin với trang cũng tránh được chi phí mở một kết nối mới.
Với Shopify và công việc theme
Hướng dẫn theme của Shopify khuyên chỉ lazy-load các ảnh nằm dưới màn hình đầu, yêu cầu kích thước hiển thị thay vì một tệp lớn hơn bị thu nhỏ trong trình duyệt, và dùng ảnh responsive thông qua image tag của nền tảng. Đó là cùng những nguyên tắc áp dụng cho Liquid. Khi chúng tôi xây dựng hoặc audit storefront qua dịch vụ của mình, ảnh hero là thứ đầu tiên chúng tôi kiểm tra, và các theme của chúng tôi được phát hành với điều đó trong đầu.