KIếN THứC WEBSITE › PERFORMANCE

Lazy load image — 5 bước implement và benchmark

Lazy load image 2026 — 5 bước implement và benchmark

Lazy load image hoãn tải ảnh phần dưới trang cho đến khi người dùng cuộn đến — giảm LCP và tiết kiệm băng thông. Bài hướng dẫn 5 bước 2026: native loading="lazy", IntersectionObserver, priority hint, debug pitfall và lỗi phổ biến trên WordPress.

Lazy load image — concept và các cách triển khai

Lazy load image — concept và các cách triển khai
Lazy load image — concept và các cách triển khai

Lazy load hoãn tải tài nguyên (ảnh, iframe, video) cho đến khi sắp vào vùng hiển thị. Trình duyệt hiện đại hỗ trợ qua attribute loading="lazy" native, không cần JavaScript.

Kỹ thuật này giảm đáng kể dữ liệu tải ban đầu cho trang có nhiều ảnh ở phần dưới.

Native so với JavaScript-based lazy load

  • Native (loading="lazy"): trình duyệt tự xử lý, không cần JS. Hỗ trợ Chrome 76+, Firefox 75+, Safari 15.4+, Edge 79+.
  • Độ phủ native lazy load đạt ~96% toàn cầu năm 2026 — đủ để dùng làm mặc định cho mọi dự án.
  • IntersectionObserver: JS-based, kiểm soát linh hoạt hơn. Hỗ trợ ~99% nhưng cần JS chạy.
  • Kết hợp tối ưu: native mặc định, IntersectionObserver cho trường hợp cần tuỳ biến cao.

Tác động đến LCP và Core Web Vitals

Lazy load đúng cách giảm số byte tải ban đầu, từ đó cải thiện LCP. Xem thêm tại bài tối ưu LCPtổng quan Core Web Vitals 2026.

Cảnh báo: lazy load sai — áp dụng lên ảnh hero — sẽ làm LCP tệ hơn đáng kể.

Lazy load và bandwidth thực tế

Trang danh mục sản phẩm với 48 thumbnail: nếu không lazy, trình duyệt tải toàn bộ khi mở trang. Với lazy load, chỉ 6–8 ảnh phần đầu trang được tải ngay.

Tiết kiệm băng thông rõ nhất với người dùng di động thoát trước khi cuộn xuống — phổ biến trên trang category.

Cách 1 — Native loading=”lazy”

Cách đơn giản nhất: thêm loading="lazy" vào mọi <img> ở phần dưới trang. WordPress 5.5+ tự động thêm cho ảnh trong nội dung, bỏ qua ảnh đầu tiên.

Plugin “Native Lazy Load” cho phép tuỳ chỉnh logic mặc định nếu cần kiểm soát chi tiết hơn.

Markup chuẩn — dưới và trên trang

<!-- Ảnh phần dưới trang: lazy load -->
<img src="/product-2.webp" alt="Sản phẩm 2"
     width="600" height="400"
     loading="lazy"
     decoding="async">

<!-- Ảnh hero/LCP phần đầu: KHÔNG lazy -->
<img src="/hero.webp" alt="Hero"
     width="1920" height="1080"
     fetchpriority="high"
     decoding="sync">

4 quy tắc khi dùng native lazy

  • Luôn set width + height: giữ chỗ trước khi ảnh load, tránh dịch chuyển bố cục (CLS).
  • Thêm decoding="async": giảm thời gian chặn main thread khi giải mã ảnh.
  • KHÔNG lazy ảnh hero hoặc LCP: lazy ảnh đầu trang sẽ làm chậm điểm LCP nghiêm trọng.
  • Test trên DevTools: tab Network → xác nhận ảnh chỉ load khi cuộn đến, không load khi mở trang.

WordPress 5.5+ và native lazy

WordPress tự động thêm loading="lazy" cho mọi ảnh qua hàm wp_lazy_loading_enabled. Ảnh đầu tiên trong nội dung được bỏ qua — nhưng WordPress không biết đâu là ảnh LCP thật sự.

Cần thêm filter thủ công để tắt lazy cho ảnh featured image hoặc hero trong template.

IntersectionObserver và Priority hint

IntersectionObserver và Priority hint
IntersectionObserver và Priority hint

Native loading="lazy" có ngưỡng cố định không tuỳ chỉnh được — khoảng 3000px trước vùng hiển thị trên di động. Khi cần kiểm soát linh hoạt hơn, dùng IntersectionObserver.

Use case phổ biến: ngưỡng tải tuỳ chỉnh, hiệu ứng fade-in khi ảnh xuất hiện, lazy load ảnh nền CSS.

Code IntersectionObserver cơ bản

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.classList.add('loaded');
      observer.unobserve(img);
    }
  });
}, {
  rootMargin: '200px 0px',
  threshold: 0.01
});

document.querySelectorAll('img[data-src]').forEach(img => {
  observer.observe(img);
});

Markup pattern data-src

<img src="/placeholder-1x1.svg"
     data-src="/product-real.webp"
     alt="Sản phẩm"
     width="600" height="400"
     class="lazy">

<style>
img.lazy { opacity: 0; transition: opacity 0.4s; }
img.lazy.loaded { opacity: 1; }
</style>

Khi nào nên dùng IntersectionObserver thay native

Dùng IntersectionObserver khi cần: ngưỡng tải tuỳ chỉnh, fade-in animation, lazy load ảnh nền CSS hoặc lazy load trong carousel.

Lưu ý quan trọng: không dùng cả hai cùng lúc cho cùng một nhóm ảnh — sẽ gây tải trùng lặp.

Priority hint cho hero và LCP

Trình duyệt xếp hàng ưu tiên tải ảnh. Mặc định ảnh trong vùng hiển thị là “auto”, phần dưới là “low”.

Ảnh hero và LCP nên đặt fetchpriority="high" để trình duyệt ưu tiên ngay từ khi phân tích HTML.

3 mức fetchpriority và use case

  • fetchpriority=”high”: ảnh hero, element LCP, ảnh sản phẩm chính trang chi tiết.
  • fetchpriority=”low”: ảnh trang trí nền, slide carousel từ vị trí thứ 2 trở đi.
  • Mặc định (auto): mọi ảnh còn lại — trình duyệt tự quyết theo vị trí trong trang.

Pattern cho hero WordPress

<?php $hero_id = get_post_thumbnail_id(); ?>
<img src="<?php echo wp_get_attachment_image_url($hero_id, 'large'); ?>"
     srcset="<?php echo wp_get_attachment_image_srcset($hero_id, 'large'); ?>"
     sizes="(max-width: 768px) 100vw, 800px"
     alt="<?php echo get_the_title(); ?>"
     width="800" height="600"
     fetchpriority="high"
     decoding="sync">

Preload ảnh LCP trong head

Với ảnh LCP quan trọng, thêm <link rel="preload"> trong <head> để trình duyệt bắt đầu tải trước khi phân tích body HTML.

Kết hợp preload với fetchpriority="high" cho LCP image — đây là cách hiệu quả nhất để tối ưu điểm LCP trên trang sản phẩm.

Debug và tránh pitfall

Debug và tránh pitfall
Debug và tránh pitfall

Lazy load đơn giản nhưng dễ gây lỗi tinh vi. Kiểm tra qua Chrome DevTools tab Network và Coverage để xác nhận ảnh load đúng thời điểm.

5 pitfall phổ biến

  • Lazy load ảnh hero: WordPress tự thêm lazy cho mọi ảnh, kể cả ảnh đầu tiên. Tắt cho phần tử LCP qua filter wp_lazy_loading_enabled.
  • Quên width/height: CLS tăng vọt khi ảnh load. Đặt attribute rõ hoặc dùng CSS aspect-ratio.
  • Xung đột native và JS: dùng cả hai cùng lúc khiến ảnh tải 2 lần. Chỉ chọn một phương pháp.
  • Ảnh nền CSS không lazy: background-image load ngay khi phân tích stylesheet. Chuyển sang <img> hoặc dùng IntersectionObserver toggle class.
  • Ảnh trong print stylesheet: ảnh nền trong media="print" vẫn tải. Dùng inline style hoặc lazy CSS class.

Workflow debug trên DevTools

Mở DevTools → tab Network → lọc “Img” → reload trang. Xác nhận: chỉ 6–10 ảnh đầu trang load khi trang mở.

Cuộn xuống → ảnh phần dưới bắt đầu load. Nếu toàn bộ ảnh load ngay khi mở: lazy chưa hoạt động hoặc bị override.

Kiểm tra attribute trong Elements panel để xác định nguyên nhân.

Checklist triển khai cho shop WordPress VN

Danh sách kiểm tra trước khi bàn giao. Áp dụng cho trang sản phẩm, danh mục và blog.

Checklist kỹ thuật

  1. Xác nhận ảnh hero KHÔNG có loading="lazy" và đã có fetchpriority="high".
  2. Mọi <img> phần dưới trang có loading="lazy"decoding="async".
  3. Mọi <img>widthheight attribute.
  4. WordPress filter tắt lazy load cho featured image đầu tiên.
  5. Plugin lazy (nếu dùng) không chồng lên native lazy của WordPress.
  6. Ảnh nền CSS quan trọng đã chuyển sang <img> hoặc có lazy CSS riêng.
  7. Slide carousel: slide 1 không lazy, slide 2+ có loading="lazy" hoặc data-src.
  8. Xác nhận trên DevTools Network với throttle “Mobile 4G”.

Tối ưu thêm với format ảnh

Lazy load kết hợp với format ảnh đúng (WebP/AVIF) mang lại hiệu quả tối đa. Xem thêm tại bài so sánh WebP và AVIF.

Với shop nhiều ảnh sản phẩm, bộ ba lazy load + WebP + srcset đúng kích thước là tối ưu ảnh cơ bản cần triển khai trước.

Bài liên quan

Lazy load là một phần của bộ kỹ thuật tối ưu ảnh. Đọc thêm các bài liên quan trong cùng nhóm.

Câu hỏi thường gặp

Native loading=”lazy” có hỗ trợ iOS Safari không?

Safari iOS 15.4+ (tháng 3/2022) hỗ trợ native lazy. Độ phủ ~95% người dùng iOS năm 2026.

iOS 14 trở xuống không hỗ trợ native. Nếu cần phủ nhóm nhỏ này, thêm IntersectionObserver làm dự phòng.

WordPress auto lazy có xung đột với plugin lazy load không?

Có. WordPress 5.5+ tự thêm native lazy.

Plugin lazy (Smush, A3 Lazy Load) có thể khiến ảnh tải 2 lần.

Tắt native qua add_filter('wp_lazy_loading_enabled', '__return_false') nếu để plugin xử lý toàn bộ.

Lazy load có giúp cải thiện thứ hạng Google không?

Gián tiếp — lazy load giảm LCP, LCP là chỉ số Core Web Vitals tác động đến xếp hạng. Nhưng lazy sai (áp lên ảnh hero) làm LCP tệ hơn và có thể hại xếp hạng.

Kiểm tra dữ liệu thực tế trong Search Console sau khi triển khai, không chỉ dựa vào kết quả lab.

Ảnh trong slider/carousel nên lazy thế nào?

Slide 1 visible: không lazy, thêm fetchpriority="high". Slide 2 trở đi: lazy.

Thư viện JS slider như Swiper, Glide có option preloadImages: false. Hoặc đặt data-src cho slide 2+ và swap khi người dùng nhấn next.

Lazy load có hoạt động với ảnh trong WooCommerce không?

Có. WooCommerce dùng hook wp_get_attachment_image — WordPress tự thêm native lazy cho ảnh sản phẩm trong grid.

Ảnh featured image trang sản phẩm đơn cần tắt lazy và bật fetchpriority="high" thủ công trong template.

Muốn audit và tối ưu toàn diện hiệu năng ảnh cho shop? Xem dịch vụ tối ưu Core Web Vitals của Web22 — bao gồm lazy load, srcset và cấu hình CDN.