Technical SEO

Intersection Observer API

Giao diện lập trình cho phép theo dõi sự xuất hiện của phần tử trong khung nhìn để kích hoạt lazy loading hoặc hiệu ứng chính xác.

3 lượt xem Cập nhật: 29/05/2026

Intersection Observer API là gì?

Intersection Observer API là một giao diện lập trình (API) của trình duyệt cho phép theo dõi xem một phần tử HTML có xuất hiện trong khung nhìn (viewport) hay không — mà không cần dùng scroll event hay tính toán vị trí thủ công bằng getBoundingClientRect(). Đây là công cụ nền tảng để triển khai lazy loading ảnh, video, iframe hoặc kích hoạt hiệu ứng khi cuộn trang — một cách nhẹ nhàng, hiệu quả và thân thiện với hiệu năng.

Tại sao quan trọng trong SEO?

Intersection Observer API ảnh hưởng trực tiếp đến ba yếu tố cốt lõi của Technical SEO: tốc độ tải trang, trải nghiệm người dùng (UX), và khả năng thu thập dữ liệu của bot tìm kiếm.

  • Tăng tốc độ hiển thị nội dung chính: Bằng cách chỉ tải ảnh hoặc thành phần không thiết yếu khi chúng gần vào khung nhìn, thời gian First Contentful Paint (FCP)Largest Contentful Paint (LCP) được cải thiện rõ rệt — hai chỉ số nằm trong Core Web Vitals.
  • Giảm băng thông và tài nguyên máy chủ: Tránh tải hàng chục ảnh ẩn ở cuối trang giúp giảm tổng kích thước trang (page weight), đặc biệt trên mạng di động chậm — điều Google đánh giá cao trong xếp hạng mobile-first.
  • Hỗ trợ bot thu thập dữ liệu: Các bot như Googlebot hiện hỗ trợ Intersection Observer từ Chrome 74 trở lên. Nếu phần tử được lazy load bằng cách này, bot vẫn đọc được thẻ <img> gốc (có src hoặc srcset hợp lệ), không bị chặn như các giải pháp dựa hoàn toàn vào JavaScript không có fallback.

Lưu ý: API này không thay thế lazy loading bằng thuộc tính loading="lazy" (HTML native), nhưng lại là lựa chọn bắt buộc khi cần kiểm soát chi tiết hơn — ví dụ: tải ảnh khi phần tử còn cách viewport 200px, hoặc kích hoạt hiệu ứng fade-in chỉ khi hiện đủ 30% diện tích.

Cách hoạt động

Intersection Observer hoạt động theo mô hình observer-pattern: bạn tạo một đối tượng quan sát (IntersectionObserver), đăng ký các phần tử cần theo dõi, và định nghĩa hàm xử lý khi trạng thái giao cắt thay đổi.

Khi một phần tử “giao cắt” với vùng quan sát (thường là viewport, nhưng có thể là phần tử cha tùy chọn), trình duyệt sẽ gọi callback với danh sách các đối tượng IntersectionObserverEntry, chứa thông tin như:

  • isIntersecting: true nếu phần tử đang trong khung nhìn (hoặc vượt ngưỡng)
  • intersectionRatio: tỷ lệ phần trăm diện tích phần tử hiện trong viewport (từ 0 đến 1)
  • boundingClientRect: vị trí và kích thước phần tử so với viewport

Quá trình này không gây layout thrashing vì được thực hiện ngoài luồng render — khác biệt lớn so với việc dùng window.addEventListener('scroll', ...).

Hướng dẫn thực hiện

  1. Khởi tạo Observer:
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          loadMedia(entry.target);
          observer.unobserve(entry.target); // tắt quan sát sau khi tải
        }
      });
    }, {
      rootMargin: '0px 0px 200px 0px', // tải trước khi vào viewport 200px
      threshold: 0.1 // kích hoạt khi 10% phần tử hiện ra
    });
  2. Đăng ký phần tử cần theo dõi:
    document.querySelectorAll('img[data-src]').forEach(img => {
      observer.observe(img);
    });

    Lưu ý: Ảnh phải có thuộc tính data-src (nguồn thật), còn src giữ giá trị placeholder (ví dụ: data:image/svg+xml,...) hoặc để trống.

  3. Hàm tải media an toàn:
    function loadMedia(el) {
      const src = el.getAttribute('data-src');
      const srcset = el.getAttribute('data-srcset');
      if (src) el.src = src;
      if (srcset) el.srcset = srcset;
      el.removeAttribute('data-src');
      el.removeAttribute('data-srcset');
      el.classList.add('loaded');
    }
  4. Thêm fallback cho trình duyệt cũ:

    Dùng @supports hoặc kiểm tra sự tồn tại của IntersectionObserver để bật lazy loading native hoặc fallback bằng scroll event — tùy trường hợp.

Lỗi thường gặp

Lỗi Nguồn gốc Cách khắc phục
Ảnh không tải dù đã cuộn tới Thiếu observer.unobserve() hoặc phần tử bị xóa/kích hoạt nhiều lần Luôn gọi unobserve() sau khi tải xong; kiểm tra phần tử chưa bị display: none hoặc visibility: hidden trước khi quan sát
Googlebot không thấy ảnh Dùng src trống thay vì placeholder hợp lệ, hoặc thiếu thẻ <noscript> tương ứng Luôn giữ src có giá trị hợp lệ (placeholder SVG hoặc ảnh nhỏ); đảm bảo ảnh xuất hiện trong DOM ban đầu, không tạo động bằng JS
Hiệu năng giảm trên thiết bị低端 Quan sát quá nhiều phần tử cùng lúc (trên 50–100) Hạn chế số phần tử quan sát; kết hợp với debounce nhẹ nếu cần xử lý phức tạp; ưu tiên loading="lazy" cho ảnh tiêu chuẩn

Ví dụ thực tế

Một trang tin tức có 42 ảnh trong bài viết dài. Khi áp dụng Intersection Observer với rootMargin: '0px 0px 300px 0px'threshold: 0.01:

  • Chỉ 8 ảnh đầu tiên (phần trên màn hình) được tải ngay lúc khởi tạo.
  • Ảnh thứ 9–16 bắt đầu tải khi người dùng cuộn xuống còn cách 300px — đủ thời gian tải trước khi hiện ra.
  • Tổng kích thước trang giảm từ 4.2 MB xuống còn 1.1 MB ở lần tải đầu tiên.
  • LCP cải thiện từ 4.8s → 1.9s trên mạng 3G giả lập (theo Lighthouse).
Lưu ý: Kết quả đo được phụ thuộc vào cấu trúc DOM, CDN, và chiến lược nén ảnh — không phải con số cố định.

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

Intersection Observer có thay thế lazy loading HTML native không?

Không. loading="lazy" đơn giản, hỗ trợ rộng và nên dùng cho ảnh/video cơ bản. Intersection Observer dành cho trường hợp cần kiểm soát ngưỡng, hiệu ứng, hoặc xử lý logic phức tạp (ví dụ: tải ảnh chỉ khi người dùng dừng cuộn 200ms).

API này có hoạt động trên tất cả trình duyệt?

Hỗ trợ từ Chrome 51, Firefox 55, Edge 79, Safari 12.2. Với Safari dưới 12.2 hoặc IE, cần polyfill (ví dụ: intersection-observer từ w3c). Tỷ lệ người dùng không hỗ trợ hiện tại (2024) dưới 0.3% — có thể bỏ qua hoặc dùng fallback nhẹ.

Có ảnh hưởng đến SEO nếu dùng sai cách?

Có. Nếu ảnh không xuất hiện trong DOM ban đầu (ví dụ: tạo toàn bộ bằng JavaScript), hoặc dùng src="" mà không có placeholder hợp lệ, Googlebot có thể không thu thập được ảnh — làm mất cơ hội hiển thị trong Tìm kiếm Hình ảnh. Luôn đảm bảo ảnh tồn tại trong HTML nguồn với thuộc tính data-src, không phải src trống.