Lazy loading thực sự tác động thế nào đến Largest Contentful Paint của bạn
Lazy loading hữu ích, nhưng không phải là cách sửa hiệu năng áp dụng cho mọi trường hợp. Với LCP, nó có thể giúp, gây hại hoặc không tạo khác biệt, tùy vào tài nguyên nào bị trì hoãn.
Mục lục
- Lazy loading là một quyết định lập lịch, không phải câu thần chú tăng tốc
- Trình duyệt làm gì khi bạn lazy load một ảnh
- Quy tắc đơn giản: không bao giờ lazy load ứng viên LCP
- Sửa lại: dùng đúng URL nội bộ thực tế
- Khi lazy loading có thể cải thiện LCP
- Mẫu tốt hơn cho ảnh LCP
- Ảnh nền cần được chú ý kỹ hơn
- Lazy loading bằng JavaScript thường làm mọi thứ tệ hơn
- LCP không phải lúc nào cũng là vấn đề ảnh
- Cách kiểm thử thay đổi lazy loading mà không tự đánh lừa mình
- Một chính sách thực tế cho hầu hết website
Lazy loading là một quyết định lập lịch, không phải câu thần chú tăng tốc
Lazy loading thường được mô tả như một cải tiến hiệu năng, điều này đúng theo cách tương tự như việc không xếp đồ vào vali là một cách giảm trọng lượng. Nó giúp ích vì trình duyệt phải làm ít việc hơn ngay từ đầu.
Sự phân biệt đó rất quan trọng với Largest Contentful Paint, thường được viết tắt là LCP. LCP đo thời điểm phần tử có ý nghĩa lớn nhất trong viewport được render. Trên nhiều trang, phần tử đó là ảnh hero. Trên những trang khác, đó có thể là một tiêu đề lớn, ảnh poster, ảnh sản phẩm hoặc một khối nội dung.
Lazy loading thay đổi thời điểm tài nguyên được yêu cầu. Nó không làm ảnh decode nhanh hơn, máy chủ phản hồi nhanh hơn hay font render sớm hơn. Nếu bạn lazy load sai thứ, đặc biệt là phần tử trở thành LCP, bạn đang bảo trình duyệt chờ trước khi tải chính thứ nó phải hiển thị để vượt qua Core Web Vitals.
Đó là lý do lazy loading vừa bị lạm dụng vừa chưa được hiểu đầy đủ.
Trình duyệt làm gì khi bạn lazy load một ảnh
Lazy loading ảnh gốc của trình duyệt thường được thêm như sau:
<img src='hero.jpg' loading='lazy' alt='...'>
Với loading='lazy', trình duyệt được phép hoãn việc tải ảnh cho đến khi nó tin rằng ảnh có khả năng sắp được cần đến. Trên thực tế, trình duyệt dùng khoảng cách tới viewport, điều kiện mạng, kích thước ảnh và các heuristic khác. Quy tắc chính xác là chi tiết triển khai và có thể thay đổi.
Với loading='eager', hoặc khi không có thuộc tính lazy trong hầu hết trường hợp, trình duyệt xem ảnh là một phần của quy trình tải bình thường. Nó vẫn phải ưu tiên giữa CSS, JavaScript, font, ảnh và các request khác, nhưng ảnh có thể được phát hiện ngay lập tức.
Điều này có nghĩa lazy loading chủ yếu ảnh hưởng đến ba giai đoạn:
- Discovery: khi trình duyệt nhận thấy tài nguyên.
- Request start: khi việc tải qua mạng bắt đầu.
- Render timing: khi tài nguyên cuối cùng có thể được decode và paint.
Với LCP, phần nguy hiểm là request start. Nếu request ảnh LCP bắt đầu muộn, mọi thứ sau đó cũng bị đẩy muộn theo.
Quy tắc đơn giản: không bao giờ lazy load ứng viên LCP
Nếu một ảnh hiển thị trong viewport ban đầu và có khả năng là phần tử contentful lớn nhất, đừng lazy load nó.
Điều này bao gồm:
- ảnh hero
- ảnh sản phẩm chính nằm trên màn hình đầu tiên
- ảnh lead lớn của bài viết
- ảnh lớn kiểu background nhưng được triển khai bằng
<img> - ảnh poster video khi poster là yếu tố hình ảnh chính
Trình duyệt không thể render ảnh LCP cho đến khi ảnh đó được yêu cầu, truyền tải, decode và paint. Lazy loading chèn thêm sự bất định trước bước đầu tiên. Ngay cả một độ trễ nhỏ cũng có thể đủ để đẩy LCP từ mức chấp nhận được sang kém trên kết nối chậm hơn.
Một mẫu lỗi phổ biến trông như sau:
- Máy chủ gửi HTML.
- Trình duyệt parse một ảnh nằm trên màn hình đầu tiên.
- Ảnh có
loading='lazy'. - Trình duyệt chờ vì heuristic lazy-loading cho rằng nó có thể chờ.
- CSS và JavaScript tiếp tục tải.
- Request ảnh bắt đầu muộn hơn mức nên có.
- LCP bị trễ, dù bản thân file ảnh đã được tối ưu khá hợp lý.
Điều này gây khó chịu vì trang có thể trông gọn gàng trong code review. Vấn đề không chỉ là kích thước file. Đó là độ ưu tiên.
Nếu bạn đang đọc kết quả lab và cố xác định liệu LCP có thực sự là vấn đề hay không, hướng dẫn của chúng tôi về cách đọc báo cáo Lighthouse mà không hoảng là một tài liệu thực dụng có chủ ý: hãy tách dữ liệu thực địa, gợi ý từ lab và các cách sửa trước khi bắt đầu đổi code. (Lưu ý: nếu routing của bạn phân biệt chữ hoa chữ thường, hãy dùng đúng URL từ CMS.)
Sửa lại: dùng đúng URL nội bộ thực tế
URL bài viết Wux chính xác là Cách đọc báo cáo Lighthouse mà không hoảng. Ý chính vẫn giữ nguyên: hãy xác định phần tử LCP trước khi thay đổi hành vi tải.
Khi lazy loading có thể cải thiện LCP
Lazy loading có thể cải thiện LCP một cách gián tiếp khi nó giữ các tài nguyên không quan trọng tránh đường cho trình duyệt.
Hãy hình dung một trang sản phẩm có ảnh sản phẩm hero ở đầu trang và một carousel gồm mười hai ảnh đề xuất nằm dưới màn hình đầu tiên. Nếu cả mười ba ảnh đều được tải eager, trình duyệt có thể tiêu tốn băng thông và slot kết nối cho những ảnh người dùng chưa thể thấy. Trên mạng bị giới hạn, điều đó có thể cạnh tranh với ảnh hero, CSS hoặc file font.
Lazy loading các ảnh carousel dưới màn hình đầu tiên có thể giúp ảnh LCP tải sớm hơn vì có ít request không quan trọng hơn cạnh tranh trong quá trình tải trang ban đầu.
Đây là trường hợp hiệu năng hợp lệ cho lazy loading:
- eager load ứng viên LCP nằm trên màn hình đầu tiên
- lazy load ảnh bên dưới viewport ban đầu
- tránh các script nặng chèn ảnh quan trọng muộn
- giữ kích thước ảnh trong HTML để tránh layout shift
Lazy loading tự thân không phải là một tối ưu LCP. Nó là công cụ ưu tiên tài nguyên. Nó hữu ích khi bảo vệ critical path.
Mẫu tốt hơn cho ảnh LCP
Với ảnh LCP nằm trên màn hình đầu tiên, mục tiêu là để trình duyệt phát hiện ảnh sớm, request sớm và render mà không gây mất ổn định bố cục.
Một baseline vững chắc trông như sau:
<img
src='/images/product-hero.avif'
srcset='/images/product-hero-800.avif 800w, /images/product-hero-1400.avif 1400w'
sizes='(max-width: 768px) 100vw, 720px'
width='1400'
height='900'
loading='eager'
fetchpriority='high'
decoding='async'
alt='Black hiking backpack with roll-top closure'
>
Những phần quan trọng không phải là trang trí:
loading='eager'ngăn độ trễ do lazy-loading.fetchpriority='high'cho trình duyệt biết ảnh này quan trọng.widthvàheightgiữ chỗ và giảm layout shift.srcsetvàsizesngăn tải file quá lớn.- Định dạng hiện đại có thể giảm thời gian truyền tải khi được dùng cẩn thận.
Nếu bạn vẫn đang phục vụ một file JPEG lớn duy nhất cho mọi màn hình, định dạng ảnh và kích thước responsive có thể quan trọng hơn thuộc tính lazy-loading. Để có cây quyết định thực tế, xem khi nào AVIF vượt WebP và khi nào thì không.
Ảnh nền cần được chú ý kỹ hơn
Ảnh nền CSS không được phát hiện sớm như ảnh HTML thông thường. Trình duyệt phải tải và parse CSS trước khi biết về chúng. Nếu phần tử LCP của bạn là ảnh nền CSS, bạn đã khiến discovery khó hơn.
Điều đó không có nghĩa ảnh nền bị cấm. Nó có nghĩa bạn nên dùng chúng một cách có chủ đích.
Với ảnh trang trí, CSS background là ổn. Với hình ảnh hero có ý nghĩa, phần tử <img> hoặc <picture> thường tốt hơn vì nó hiển thị với HTML parser, hỗ trợ alt text và hoạt động tốt với các thuộc tính ảnh responsive.
Nếu bạn bắt buộc phải dùng CSS background cho ảnh LCP, hãy cân nhắc preload nó:
<link rel='preload' as='image' href='/images/hero.avif'>
Preload cũng không phải cây đũa thần. Preload quá nhiều ảnh sẽ tạo ra cùng một vấn đề ưu tiên trong một hình dạng khác. Hãy dùng nó cho một ảnh thực sự quan trọng, không phải cho mọi ảnh trong design system.
Lazy loading bằng JavaScript thường làm mọi thứ tệ hơn
Trước khi lazy loading gốc được hỗ trợ rộng rãi, nhiều site dùng thư viện JavaScript để đổi data-src thành src sau khi tải trang hoặc sau khi intersection observer được kích hoạt. Một số site vẫn làm vậy.
Điều này có thể hợp lý với các trang bài viết dài hoặc gallery nhiều ảnh. Nhưng đó là lựa chọn kém cho nội dung nằm trên màn hình đầu tiên.
Browser preload scanner rất nhanh, nhưng nó không thể request một ảnh có URL bị giấu trong thuộc tính tùy chỉnh cho đến khi JavaScript chạy. Nếu ảnh hero của bạn bắt đầu là data-src='hero.jpg', bạn đã trì hoãn discovery sau việc tải script, parse, thực thi và framework hydration.
Đó là một đánh đổi tệ cho LCP. Hãy đặt URL ảnh quan trọng trong HTML thật. Để trình duyệt làm việc của nó.
LCP không phải lúc nào cũng là vấn đề ảnh
Trên một số trang, phần tử LCP là văn bản. Trong trường hợp đó, lazy loading ảnh có thể có rất ít tác động trực tiếp. Nút thắt của bạn có thể là CSS chặn render, phản hồi máy chủ chậm, client-side rendering hoặc web font.
Font đáng được nhắc riêng vì chúng là nguyên nhân ẩn thường gặp khiến văn bản render muộn. Một tiêu đề lớn có thể trở thành LCP, và hành vi tải font có thể trì hoãn hoặc làm thay đổi thời điểm tiêu đề đó được paint. Nếu các thay đổi về ảnh không làm chỉ số dịch chuyển, hãy kiểm tra trực tiếp phần tử LCP thay vì giả định. Bài viết của chúng tôi về web font như một chiến thắng hiệu năng trình bày những cách sửa nhàm chán nhưng thường hiệu quả: ít weight hơn, định dạng hiện đại, fallback hợp lý.
Cách kiểm thử thay đổi lazy loading mà không tự đánh lừa mình
Đừng kiểm thử bằng cách nhìn chằm chằm vào trang trên Wi-Fi văn phòng. Bạn cần thấy timing của request.
Dùng workflow này:
- Mở Chrome DevTools và ghi một Performance trace.
- Bật network throttling, chẳng hạn Fast 4G hoặc Slow 4G.
- Tải lại trang với cache bị tắt.
- Tìm marker LCP.
- Xác định phần tử LCP.
- Trong panel Network, kiểm tra thời điểm tài nguyên đó bắt đầu tải.
Nếu tài nguyên LCP bắt đầu muộn, hãy hỏi vì sao:
- Nó có bị lazy load không?
- Nó có được JavaScript chèn vào không?
- Nó có bị giấu trong CSS không?
- Nó có bị hạ ưu tiên sau các ảnh khác không?
- Máy chủ có phản hồi chậm không?
Sau đó thực hiện một thay đổi và kiểm thử lại. Công việc hiệu năng trở nên rối khi các nhóm thay đổi định dạng ảnh, lazy loading, preloading, bundle JavaScript và thiết lập CDN trong cùng một lần triển khai. Bạn có thể cải thiện trang, nhưng sẽ không biết thay đổi nào tạo ra khác biệt.
Dữ liệu thực địa cũng quan trọng. Công cụ lab hữu ích cho chẩn đoán, nhưng LCP thay đổi theo thiết bị, mạng, viewport, trạng thái cache và địa lý. Hãy dùng real-user monitoring hoặc dữ liệu Chrome User Experience Report khi có thể.
<!-- tool-cta:start -->
💡 Hãy thử cách này: Giữ hình ảnh LCP của bạn nhỏ và được tải ưu tiên bằng cách xử lý nó qua Image Compressor, để nó hiển thị nhanh mà không cần lazy loading.
<!-- tool-cta:end -->
Một chính sách thực tế cho hầu hết website
Với hầu hết site marketing, trang ecommerce, site tài liệu và trang publisher, chính sách này là đủ:
- Ảnh chính nằm trên màn hình đầu tiên: tải eager, cân nhắc fetch priority cao.
- Ảnh nội dung dưới màn hình đầu tiên: lazy load.
- Icon và asset UI rất nhỏ: thường không đáng để cân nhắc riêng lẻ.
- Hero dạng CSS background: cân nhắc lại thành ảnh HTML hoặc preload cẩn thận.
- Ảnh hero được JavaScript chèn vào: sửa kiến trúc render nếu có thể.
- Carousel: chỉ eager load slide đầu tiên đang hiển thị; lazy load phần còn lại.
Có các trường hợp ngoại lệ. Heuristic của trình duyệt được cải thiện. Framework thêm component ảnh tự động. Một số nền tảng hiện tránh lazy loading những ảnh được phát hiện gần viewport. Tuy vậy, nguyên tắc không đổi: tài nguyên quan trọng nên xuất hiện sớm và rõ ràng; tài nguyên không quan trọng nên chờ.
Lazy loading có giá trị khi nó diễn đạt được sự phân biệt đó. Nó gây hại khi che giấu nội dung quan trọng nhất khỏi trình duyệt cho đến sau khi trang đã bắt đầu thua trong cuộc đua LCP.