ResizeObserver
memberi tahu Anda saat ukuran elemen berubah.
Sebelum ResizeObserver
, Anda harus menambahkan pemroses ke peristiwa resize
dokumen agar mendapatkan notifikasi terkait perubahan apa pun pada dimensi area pandang. Dalam 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 layout
thrashing jika Anda tidak mengurus batch semua operasi baca dan semua
penulisan.
Hal ini bahkan tidak mencakup kasus saat elemen berubah ukurannya tanpa mengubah ukuran jendela
utama. Misalnya, menambahkan turunan baru, menyetel
gaya display
elemen ke none
, atau tindakan serupa dapat mengubah ukuran
elemen, pasangannya, atau ancestornya.
Inilah alasan ResizeObserver
adalah primitif yang berguna. Sistem ini bereaksi terhadap perubahan
ukuran elemen apa pun yang diamati, terlepas dari penyebab perubahan.
Fungsi ini juga memberikan akses ke ukuran baru dari elemen yang diamati.
API
Semua API dengan akhiran Observer
yang kami sebutkan di atas memiliki desain API
yang sederhana. Begitu juga dengan ResizeObserver
. Anda membuat objek ResizeObserver
dan meneruskan callback ke konstruktor. Callback mendapatkan array objek
ResizeObserverEntry
—satu entri per elemen yang diamati—yang
berisi dimensi baru untuk elemen tersebut.
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. Kotak ini
adalah kotak batas tanpa padding.
Penting untuk diperhatikan bahwa meskipun ResizeObserver
melaporkan dimensi
contentRect
dan padding, ResizeObserver
hanya menonton contentRect
.
Jangan salah membedakan contentRect
dengan kotak pembatas elemen. Kotak
pembatas, seperti yang dilaporkan oleh getBoundingClientRect()
, adalah kotak yang berisi
seluruh elemen dan turunannya. SVG merupakan 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 adalah tentang elemen yang diobservasi pada saat callback dipanggil.
borderBoxSize
contentBoxSize
devicePixelContentBoxSize
Semua item ini menampilkan array hanya baca karena di masa mendatang diharapkan 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 hal tersebut dilaporkan?
Spesifikasi ini menetapkan bahwa ResizeObserver
harus memproses semua peristiwa perubahan ukuran
sebelum menggambar dan setelah tata letak. Hal ini menjadikan callback ResizeObserver
sebagai
tempat yang ideal untuk membuat perubahan pada tata letak halaman. Karena pemrosesan ResizeObserver
terjadi antara tata letak dan paint, tindakan tersebut hanya akan membatalkan
tata letak, bukan paint.
Kena
Anda mungkin bertanya-tanya: apa yang terjadi jika saya mengubah ukuran elemen yang diamati di dalam callback ke ResizeObserver
? Jawabannya adalah: Anda akan segera memicu
panggilan lain ke callback. Untungnya, ResizeObserver
memiliki
mekanisme untuk menghindari loop callback yang tidak terbatas dan dependensi siklik. Perubahan hanya akan diproses dalam frame yang sama jika elemen yang diubah ukurannya berada lebih dalam di hierarki DOM daripada elemen shallowest yang diproses di callback sebelumnya.
Jika tidak, {i>frame<i} akan dialihkan ke {i>frame<i} berikutnya.
Aplikasi
Satu hal yang diizinkan oleh ResizeObserver
untuk Anda lakukan adalah mengimplementasikan kueri media
per elemen. Dengan mengamati elemen, Anda dapat secara imperatif menentukan
titik henti sementara desain dan mengubah gaya elemen. 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 untuk dilihat adalah jendela {i>chat<i}. Masalah yang muncul dalam tata letak percakapan umum dari atas ke bawah adalah posisi scroll. Agar tidak membingungkan pengguna, sebaiknya jendela menempel di bagian bawah percakapan, tempat pesan terbaru muncul. Selain itu, semua jenis perubahan tata letak (misalnya ponsel dari lanskap ke potret atau sebaliknya) akan mencapai hasil yang sama.
ResizeObserver
memungkinkan Anda menulis satu kode yang menangani kedua skenario. Mengubah ukuran jendela adalah peristiwa yang dapat ditangkap ResizeObserver
berdasarkan definisi, tetapi memanggil appendChild()
juga akan mengubah ukuran elemen tersebut (kecuali jika overflow: hidden
disetel), karena perlu memberi ruang untuk elemen baru. Dengan mempertimbangkan hal ini, 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 ketika pengguna men-scroll ke atas secara manual dan ingin men-scroll agar tetap berpegang pada pesan tersebut saat pesan baru masuk.
Kasus penggunaan lain adalah untuk segala jenis elemen kustom yang membuat tata letaknya sendiri.
Hingga ResizeObserver
, tidak ada cara yang efektif untuk mendapatkan notifikasi saat
dimensinya berubah sehingga turunannya dapat ditata lagi.
Efek pada Interaksi terhadap Next Paint (INP)
Interaction to Next Paint (INP) adalah metrik yang mengukur responsivitas keseluruhan halaman terhadap interaksi pengguna. Jika INP halaman berada dalam batas "baik"—yaitu, 200 milidetik atau kurang—dapat dikatakan bahwa halaman sangat responsif terhadap interaksi pengguna dengan halaman tersebut.
Meskipun jumlah waktu yang diperlukan callback peristiwa untuk dijalankan sebagai respons terhadap interaksi pengguna dapat berkontribusi secara signifikan terhadap total latensi interaksi, tetapi itu bukan satu-satunya aspek INP yang perlu dipertimbangkan. INP juga mempertimbangkan jumlah waktu yang diperlukan untuk melakukan tampilan berikutnya dari interaksi. Ini adalah jumlah waktu yang diperlukan untuk pekerjaan rendering yang diperlukan untuk mengupdate antarmuka pengguna sebagai respons terhadap interaksi untuk diselesaikan.
Jika ResizeObserver
terkait, hal ini penting karena callback yang
dijalankan instance ResizerObserver
terjadi tepat sebelum pekerjaan rendering. Hal ini
adalah desain, karena pekerjaan yang terjadi di callback harus diperhitungkan, sehingga pekerjaan tersebut kemungkinan besar memerlukan perubahan pada
antarmuka pengguna.
Berhati-hatilah dalam melakukan pekerjaan rendering seminimal yang diperlukan dalam callback ResizeObserver
, karena pekerjaan rendering yang berlebihan dapat menimbulkan situasi ketika browser tertunda dalam melakukan pekerjaan penting. Misalnya, jika interaksi 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 di callback
ResizeObserver
yang dapat memicu perubahan posisi/geometri yang dipaksakan. - Waktu yang diperlukan untuk memperbarui tata letak halaman umumnya akan meningkat seiring dengan
jumlah elemen DOM di halaman. Meskipun hal ini berlaku baik halaman menggunakan
ResizeObserver
atau tidak, pekerjaan yang dilakukan di callbackResizeObserver
dapat menjadi signifikan saat kompleksitas struktural halaman meningkat.
Kesimpulan
ResizeObserver
tersedia di semua browser
utama
dan menyediakan cara yang efisien untuk memantau perubahan ukuran elemen pada tingkat
elemen. Berhati-hatilah agar tidak menunda rendering terlalu banyak dengan API canggih ini.