ResizeObserver
memberi tahu Anda saat ukuran elemen berubah.
Sebelum ResizeObserver
, Anda harus melampirkan pemroses ke peristiwa resize
dokumen untuk mendapatkan notifikasi tentang perubahan dimensi area pandang. Di pengendali
peristiwa, Anda harus mencari tahu elemen mana yang terpengaruh oleh
perubahan tersebut dan memanggil rutinitas tertentu untuk bereaksi dengan tepat. Jika memerlukan dimensi baru elemen setelah perubahan ukuran, Anda harus memanggil getBoundingClientRect()
atau getComputedStyle()
, yang dapat menyebabkan thrashing tata letak jika Anda tidak menangani pengelompokan semua pembacaan dan semua penulisan.
Hal ini bahkan tidak mencakup kasus saat elemen mengubah ukurannya tanpa jendela
utama yang diubah ukurannya. Misalnya, menambahkan turunan baru, menetapkan gaya display
elemen ke none
, atau tindakan serupa dapat mengubah ukuran elemen, turunannya, atau ancestornya.
Itulah sebabnya ResizeObserver
adalah primitif yang berguna. Fungsi ini bereaksi terhadap perubahan
ukuran elemen yang diamati, terlepas dari apa yang menyebabkan perubahan tersebut.
Fungsi ini juga memberikan akses ke ukuran baru elemen yang diamati.
API
Semua API dengan akhiran Observer
yang kami sebutkan di atas memiliki desain API
yang sederhana. ResizeObserver
tidak terkecuali. Anda membuat objek ResizeObserver
dan meneruskan callback ke konstruktor. Callback diteruskan array objek ResizeObserverEntry
—satu entri per elemen yang diamati—yang berisi dimensi baru untuk elemen.
var ro = new ResizeObserver(entries => {
for (let entry of entries) {
const cr = entry.contentRect;
console.log('Element:', entry.target);
console.log(`Element size: ${cr.width}px x ${cr.height}px`);
console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
}
});
// Observe one or multiple elements
ro.observe(someElement);
Beberapa detail
Apa yang dilaporkan?
Umumnya,
ResizeObserverEntry
melaporkan kotak konten elemen melalui properti yang disebut
contentRect
, yang menampilkan objek
DOMRectReadOnly
. Kotak konten adalah kotak tempat konten dapat ditempatkan. Ini adalah
kotak batas dikurangi padding.
Perlu diperhatikan bahwa meskipun ResizeObserver
melaporkan dimensi
contentRect
dan padding, ResizeObserver
hanya memantau contentRect
.
Jangan keliru antara contentRect
dengan kotak pembatas elemen. Kotak
pembatas, seperti yang dilaporkan oleh getBoundingClientRect()
, adalah kotak yang berisi
seluruh elemen dan turunannya. SVG adalah pengecualian untuk aturan ini, dengan
ResizeObserver
akan melaporkan dimensi kotak pembatas.
Mulai Chrome 84, ResizeObserverEntry
memiliki tiga properti baru untuk memberikan informasi
yang lebih mendetail. Setiap properti ini menampilkan objek ResizeObserverSize
yang berisi properti blockSize
dan properti inlineSize
. Informasi
ini mengenai elemen yang diobservasi pada saat callback dipanggil.
borderBoxSize
contentBoxSize
devicePixelContentBoxSize
Semua item ini menampilkan array hanya baca karena diharapkan nantinya item tersebut dapat mendukung elemen yang memiliki beberapa fragmen, yang terjadi dalam skenario multi-kolom. Untuk saat ini, array ini hanya akan berisi satu elemen.
Dukungan platform untuk properti ini terbatas, tetapi Firefox sudah mendukung dua yang pertama.
Kapan masalah ini dilaporkan?
Spesifikasi melarang ResizeObserver
memproses semua peristiwa pengubahan ukuran
sebelum proses menggambar dan setelah tata letak. Hal ini menjadikan callback ResizeObserver
sebagai
tempat yang ideal untuk membuat perubahan pada tata letak halaman Anda. Karena pemrosesan
ResizeObserver
terjadi antara tata letak dan gambar, tindakan ini hanya akan membuat tata letak
tidak valid, bukan gambar.
Oke
Anda mungkin bertanya-tanya: apa yang terjadi jika saya mengubah ukuran elemen pengamatan
di dalam callback menjadi ResizeObserver
? Jawabannya adalah: Anda akan segera memicu
panggilan lain ke callback tersebut. Untungnya, ResizeObserver
memiliki
mekanisme untuk menghindari loop callback tanpa batas dan dependensi siklus. Perubahan hanya akan
diproses dalam frame yang sama jika elemen yang diubah ukurannya lebih dalam dalam hierarki DOM
daripada elemen paling dangkal yang diproses dalam callback sebelumnya.
Jika tidak, peristiwa akan ditangguhkan ke frame berikutnya.
Aplikasi
Satu hal yang dapat Anda lakukan ResizeObserver
adalah mengimplementasikan kueri media
per elemen. Dengan mengamati elemen, Anda dapat menentukan titik henti sementara desain
dan mengubah gaya elemen secara imperatif. Dalam
contoh berikut, kotak kedua
akan mengubah radius batasnya sesuai dengan lebarnya.
const ro = new ResizeObserver(entries => {
for (let entry of entries) {
entry.target.style.borderRadius =
Math.max(0, 250 - entry.contentRect.width) + 'px';
}
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));
Contoh menarik lainnya yang dapat dilihat adalah jendela chat. Masalah yang muncul dalam tata letak percakapan atas ke bawah yang umum adalah posisi scroll. Agar tidak membingungkan pengguna, sebaiknya jika jendela tetap ke bagian bawah percakapan, tempat pesan terbaru muncul. Selain itu, semua jenis perubahan tata letak (misalnya ponsel beralih dari lanskap ke potret atau sebaliknya) harus mencapai hal yang sama.
ResizeObserver
memungkinkan Anda menulis satu bagian kode yang menangani
kedua skenario. Mengubah ukuran jendela adalah peristiwa yang dapat
ditangkap oleh ResizeObserver
menurut definisi, tetapi memanggil appendChild()
juga akan mengubah ukuran elemen tersebut
(kecuali jikaoverflow: hidden
ditetapkan), karena perlu menyediakan ruang untuk elemen
baru. Dengan mempertimbangkan hal ini, hanya diperlukan sangat sedikit baris untuk mencapai efek
yang diinginkan:
const ro = new ResizeObserver(entries => {
document.scrollingElement.scrollTop =
document.scrollingElement.scrollHeight;
});
// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);
// Observe the timeline to process new messages
ro.observe(timeline);
Cukup rapi, bukan?
Dari sini, saya dapat menambahkan lebih banyak kode untuk menangani kasus saat pengguna men-scroll ke atas secara manual dan ingin men-scroll untuk tetap berada di pesan tersebut saat pesan baru datang.
Kasus penggunaan lainnya adalah untuk segala jenis elemen kustom yang melakukan tata letaknya sendiri.
Hingga ResizeObserver
, tidak ada cara yang andal untuk mendapatkan notifikasi saat dimensinya berubah sehingga turunannya dapat disusun ulang.
Pengaruh pada Interaction to Next Paint (INP)
Interaction to Next Paint (INP) adalah metrik yang mengukur responsivitas halaman secara keseluruhan terhadap interaksi pengguna. Jika INP halaman berada dalam nilai minimum "baik"—yaitu, 200 milidetik atau kurang—dapat dikatakan bahwa halaman responsif secara andal terhadap interaksi pengguna dengan halaman tersebut.
Meskipun jumlah waktu yang diperlukan untuk menjalankan callback peristiwa sebagai respons terhadap interaksi pengguna dapat berkontribusi secara signifikan terhadap total latensi interaksi, hal itu bukan satu-satunya aspek INP yang perlu dipertimbangkan. INP juga mempertimbangkan jumlah waktu yang diperlukan untuk gambar berikutnya interaksi terjadi. Ini adalah jumlah waktu yang diperlukan untuk menyelesaikan pekerjaan rendering yang diperlukan untuk mengupdate antarmuka pengguna sebagai respons terhadap interaksi.
Untuk ResizeObserver
, hal ini penting karena callback yang
dijalankan instance ResizerObserver
terjadi tepat sebelum pekerjaan rendering. Hal ini
didesain karena pekerjaan yang terjadi di callback harus diperhitungkan
karena pekerjaan tersebut kemungkinan besar akan memerlukan perubahan pada
antarmuka pengguna.
Pastikan untuk melakukan pekerjaan rendering sesedikit mungkin seperti yang diperlukan dalam callback
ResizeObserver
, karena pekerjaan rendering yang berlebihan dapat membuat situasi saat browser
tertunda dalam melakukan pekerjaan penting. Misalnya, jika interaksi apa pun memiliki callback yang menyebabkan callback ResizeObserver
berjalan, pastikan Anda melakukan hal berikut untuk memfasilitasi pengalaman yang selancar mungkin:
- Pastikan pemilih CSS Anda sesederhana mungkin untuk menghindari pekerjaan penghitungan ulang gaya yang berlebihan. Penghitungan ulang gaya terjadi tepat sebelum tata letak, dan pemilih CSS yang kompleks dapat menunda operasi tata letak.
- Hindari melakukan pekerjaan apa pun dalam callback
ResizeObserver
yang dapat memicu reflow paksa. - Waktu yang diperlukan untuk memperbarui tata letak halaman umumnya meningkat seiring dengan
jumlah elemen DOM di halaman. Meskipun hal ini berlaku baik halaman menggunakan
ResizeObserver
maupun tidak, pekerjaan yang dilakukan dalam callbackResizeObserver
dapat menjadi signifikan seiring meningkatnya kompleksitas struktural halaman.
Kesimpulan
ResizeObserver
tersedia di semua browser
utama
dan memberikan cara yang efisien untuk memantau pengubahan ukuran elemen di tingkat elemen. Berhati-hatilah untuk tidak menunda rendering terlalu banyak dengan API canggih ini.