IntersectionObserver memberi tahu Anda saat elemen yang diamati masuk atau keluar dari area pandang browser.
Misalnya, Anda ingin melacak kapan elemen di DOM Anda memasuki area pandang yang terlihat. Anda mungkin ingin melakukannya agar dapat memuat gambar secara lambat tepat waktu atau karena Anda perlu mengetahui apakah pengguna benar-benar melihat banner iklan tertentu. Anda dapat melakukannya dengan menghubungkan peristiwa scroll atau menggunakan timer berkala dan memanggil getBoundingClientRect()
pada elemen tersebut.
Namun, pendekatan ini sangat lambat karena setiap panggilan ke getBoundingClientRect() memaksa browser untuk menata ulang seluruh halaman dan akan menyebabkan jank yang signifikan pada situs Anda. Hal ini menjadi hampir mustahil jika Anda tahu bahwa situs Anda dimuat di dalam iframe dan Anda ingin tahu kapan pengguna dapat melihat elemen. Model Asal Tunggal dan browser tidak akan mengizinkan Anda mengakses data apa pun dari halaman web yang berisi iframe. Ini adalah masalah umum untuk iklan, misalnya, yang sering dimuat menggunakan iframe.
IntersectionObserver dirancang untuk membuat pengujian visibilitas ini lebih efisien, dan telah tersedia di semua browser modern. IntersectionObserver memberi tahu Anda saat elemen yang diamati masuk atau keluar dari area pandang browser.
Cara membuat IntersectionObserver
API ini cukup kecil, dan paling baik dijelaskan menggunakan contoh:
const io = new IntersectionObserver(entries => {
console.log(entries);
}, {
/* Using default options. Details below */
});
// Start observing an element
io.observe(element);
// Stop observing an element
// io.unobserve(element);
// Disable entire IntersectionObserver
// io.disconnect();
Dengan menggunakan opsi default untuk IntersectionObserver, callback Anda akan dipanggil saat elemen muncul sebagian dan saat elemen sepenuhnya keluar dari area pandang.
Jika Anda perlu mengamati beberapa elemen, Anda dapat dan disarankan untuk mengamati beberapa elemen menggunakan instance IntersectionObserver yang sama dengan memanggil observe() beberapa kali.
Parameter entries diteruskan ke callback Anda, yang merupakan array objek IntersectionObserverEntry. Setiap objek tersebut berisi data persimpangan yang diperbarui untuk salah satu elemen yang Anda amati.
🔽[IntersectionObserverEntry]
time: 3893.92
🔽rootBounds: ClientRect
bottom: 920
height: 1024
left: 0
right: 1024
top: 0
width: 920
🔽boundingClientRect: ClientRect
// ...
🔽intersectionRect: ClientRect
// ...
intersectionRatio: 0.54
🔽target: div#observee
// ...
rootBounds adalah hasil pemanggilan getBoundingClientRect() pada elemen root, yang merupakan area pandang secara default. boundingClientRect adalah hasil dari getBoundingClientRect() yang dipanggil pada elemen yang diamati. intersectionRect adalah persimpangan dari kedua persegi panjang ini dan secara efektif memberi tahu Anda bagian mana dari elemen yang diamati yang terlihat. intersectionRatio berkaitan erat, dan memberi tahu Anda seberapa banyak elemen yang terlihat. Dengan info ini, Anda kini dapat menerapkan fitur seperti pemuatan aset tepat waktu sebelum aset terlihat di layar. Efisien.
IntersectionObserver mengirimkan datanya secara asinkron, dan kode callback Anda akan berjalan di thread utama. Selain itu, spesifikasi sebenarnya menyatakan bahwa implementasi IntersectionObserver harus menggunakan requestIdleCallback(). Artinya, panggilan ke callback yang Anda berikan memiliki prioritas rendah dan akan dilakukan oleh browser selama waktu tidak ada aktivitas. Ini adalah keputusan desain yang disengaja.
Div scroll
Saya bukan penggemar berat scroll di dalam elemen, tetapi saya tidak di sini untuk menilai, begitu juga dengan IntersectionObserver. Objek options menggunakan opsi root yang memungkinkan Anda menentukan alternatif untuk area pandang sebagai root. Perlu diingat bahwa root harus menjadi ancestor dari semua elemen yang diamati.
Iris semua hal.
Tidak! Developer yang buruk. Hal ini tidak memperhatikan penggunaan siklus CPU pengguna Anda. Mari kita pikirkan scroller tak terbatas sebagai contoh: Dalam skenario tersebut, sebaiknya tambahkan sentinel ke DOM dan amati (dan daur ulang!) sentinel tersebut. Anda harus menambahkan sentinel di dekat item terakhir dalam scroller tanpa batas. Saat sentinel tersebut terlihat, Anda dapat menggunakan callback untuk memuat data, membuat item berikutnya, melampirkannya ke DOM, dan memosisikan ulang sentinel sebagaimana mestinya. Jika Anda mendaur ulang sentinel dengan benar, panggilan tambahan ke observe() tidak diperlukan. IntersectionObserver terus berfungsi.
More updates, please
Seperti yang disebutkan sebelumnya, callback akan dipicu satu kali saat elemen yang diamati muncul sebagian dan sekali lagi saat elemen tersebut keluar dari area pandang. Dengan cara ini, IntersectionObserver akan memberikan jawaban atas pertanyaan, "Apakah elemen X terlihat?". Namun, dalam beberapa kasus penggunaan, hal itu mungkin tidak cukup.
Di sinilah opsi threshold berperan. Dengan begitu, Anda dapat menentukan array nilai minimum intersectionRatio. Callback Anda akan dipanggil setiap kali intersectionRatio melewati salah satu nilai ini. Nilai default untuk threshold adalah [0], yang menjelaskan perilaku default. Jika kita mengubah threshold menjadi [0, 0.25, 0.5, 0.75, 1], kita akan mendapatkan notifikasi setiap kali seperempat bagian tambahan dari elemen terlihat:
Apakah ada opsi lainnya?
Saat ini, hanya ada satu opsi tambahan selain yang tercantum di atas. rootMargin memungkinkan Anda menentukan margin untuk root, sehingga Anda dapat memperbesar atau memperkecil area yang digunakan untuk persimpangan secara efektif. Margin ini ditentukan menggunakan string bergaya CSS, á la "10px 20px 30px 40px", yang menentukan margin atas, kanan, bawah, dan kiri. Singkatnya, struct opsi IntersectionObserver menawarkan opsi berikut:
new IntersectionObserver(entries => {/* … */}, {
// The root to use for intersection.
// If not provided, use the top-level document's viewport.
root: null,
// Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
// If an explicit root element is specified, components may be percentages of the
// root element size. If no explicit root element is specified, using a
// percentage is an error.
rootMargin: "0px",
// Threshold(s) at which to trigger callback, specified as a ratio, or list of
// ratios, of (visible area / total area) of the observed element (hence all
// entries must be in the range [0, 1]). Callback will be invoked when the
// visible ratio of the observed element crosses a threshold in the list.
threshold: [0],
});
<iframe> magic
IntersectionObserver dirancang khusus dengan mempertimbangkan layanan iklan dan widget jaringan sosial, yang sering menggunakan elemen <iframe> dan dapat memperoleh manfaat dari mengetahui apakah elemen tersebut terlihat. Jika <iframe> mengamati salah satu elemennya, men-scroll <iframe> serta men-scroll jendela yang berisi <iframe> akan memicu callback pada waktu yang sesuai. Namun, untuk kasus yang terakhir, rootBounds akan ditetapkan ke null untuk menghindari kebocoran data di seluruh origin.
Apa yang bukan merupakan bagian dari IntersectionObserver?
Perlu diingat bahwa IntersectionObserver sengaja tidak dibuat sempurna piksel atau latensi rendah. Menggunakannya untuk mengimplementasikan upaya seperti animasi yang bergantung pada scroll pasti akan gagal, karena data akan—secara tegas—sudah usang pada saat Anda akan menggunakannya. Penjelasan memiliki detail selengkapnya tentang kasus penggunaan asli untuk IntersectionObserver.
Berapa banyak pekerjaan yang dapat saya lakukan dalam callback?
Singkat dan Jelas: Menghabiskan terlalu banyak waktu dalam callback akan membuat aplikasi Anda lambat—semua praktik umum berlaku.
Lanjutkan dan buat elemen Anda berpotongan
Dukungan browser untuk IntersectionObserver sangat baik, karena tersedia di semua browser modern. Jika perlu, polyfill dapat digunakan di browser lama dan tersedia di repositori WICG. Tentu saja, Anda tidak akan mendapatkan manfaat performa menggunakan polyfill tersebut yang akan diberikan oleh implementasi native.
Anda dapat mulai menggunakan IntersectionObserver sekarang juga. Beri tahu kami apa yang Anda temukan.