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 mengubah ukuran, Anda harus memanggil
getBoundingClientRect()
atau getComputedStyle()
, yang dapat menyebabkan thrashing
tata letak jika Anda tidak menangani pengelompokan semua operasi baca dan semua
operasi tulis.
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, saudaranya, atau leluhurnya.
Itulah sebabnya ResizeObserver
adalah primitif yang berguna. Fungsi ini bereaksi terhadap perubahan
ukuran elemen yang diamati, terlepas dari apa yang menyebabkan perubahan tersebut.
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 mengacaukan 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 detail. Setiap properti ini menampilkan objek ResizeObserverSize
yang berisi properti blockSize
dan properti inlineSize
. Informasi
ini adalah tentang elemen yang diamati 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 gambar 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.
Gotcha
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. 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 dengan ResizeObserver
adalah menerapkan 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. Untuk menghindari kebingungan pengguna, sebaiknya jendela tetap berada di 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 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 semua 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 dengannya.
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 tugas 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
adalah karena desain, karena pekerjaan yang terjadi dalam callback harus diperhitungkan, karena hasil 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. Hanya berhati-hatilah untuk tidak menunda rendering terlalu banyak dengan API yang canggih ini.