ResizeObserver
memberi tahu Anda saat ukuran elemen berubah.
Sebelum ResizeObserver
, Anda harus melampirkan pemroses ke resize
dokumen
untuk mendapatkan notifikasi tentang setiap perubahan dimensi area pandang. Di acara
Anda kemudian harus mencari tahu elemen mana yang telah dipengaruhi oleh
perubahan itu dan memanggil rutinitas
tertentu untuk bereaksi dengan tepat. Jika Anda perlu
dimensi baru dari suatu elemen setelah
mengubah ukuran, Anda harus memanggil
getBoundingClientRect()
atau getComputedStyle()
, yang dapat menyebabkan tata letak
thrashing jika Anda tidak mengurus pengelompokan semua pembacaan dan semua
operasi tulis.
Ini bahkan tidak mencakup kasus di mana
elemen mengubah ukurannya tanpa
ukuran jendela telah diubah. Misalnya, menambahkan turunan baru, mengatur
gaya display
elemen menjadi none
, atau tindakan serupa dapat mengubah ukuran
elemen, saudara kandung, atau nenek moyangnya.
Inilah alasan ResizeObserver
adalah primitif yang berguna. Ia bereaksi terhadap perubahan dalam
ukuran elemen apa pun yang diamati, terlepas dari apa yang menyebabkan perubahan.
Fungsi ini juga memberikan akses ke ukuran baru elemen yang diamati.
API
Semua API dengan akhiran Observer
yang kami sebutkan di atas memiliki API sederhana
desain. Juga demikian untuk ResizeObserver
. Anda membuat objek ResizeObserver
dan teruskan callback ke konstruktor. Callback mendapatkan array
ResizeObserverEntry
objek—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 suatu elemen melalui properti yang disebut
contentRect
, yang menampilkan
DOMRectReadOnly
. Kotak konten adalah kotak tempat konten dapat ditempatkan. Penting
kotak pembatas tanpa {i>padding<i}.
Penting untuk diperhatikan bahwa meskipun ResizeObserver
melaporkan kedua dimensi
contentRect
dan padding, hanya mengawasi contentRect
.
Jangan keliru antara contentRect
dengan kotak pembatas elemen. Pembatas
kotak, seperti yang dilaporkan oleh getBoundingClientRect()
, adalah kotak yang berisi
seluruh elemen dan turunannya. SVG merupakan pengecualian dari aturan tersebut, dengan
ResizeObserver
akan melaporkan dimensi kotak pembatas.
Mulai Chrome 84, ResizeObserverEntry
memiliki tiga properti baru untuk memberikan lebih banyak properti
informasi terperinci. Setiap properti ini menampilkan ResizeObserverSize
objek yang berisi properti blockSize
dan properti inlineSize
. Ini
informasi tentang elemen yang diamati pada saat callback dipanggil.
borderBoxSize
contentBoxSize
devicePixelContentBoxSize
Semua item ini mengembalikan {i>array<i} {i>read-only<i} karena di masa mendatang diharapkan mendukung elemen yang memiliki beberapa fragmen, yang terjadi di 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 dilaporkan?
Spesifikasi melarang ResizeObserver
harus memproses semua peristiwa perubahan ukuran
sebelum menggambar dan setelah tata letak. Hal ini membuat callback ResizeObserver
menjadi
tempat yang ideal untuk membuat perubahan pada tata letak halaman. Karena ResizeObserver
pemrosesan terjadi antara layout dan paint, hal itu hanya akan membatalkan
tata letak, bukan cat.
Oke
Anda mungkin bertanya-tanya: apa yang terjadi jika saya mengubah ukuran objek yang diamati
di dalam callback ke ResizeObserver
? Jawabannya adalah: Anda akan memicu
panggilan lain ke callback
secara langsung. Untungnya, ResizeObserver
memiliki
mekanisme untuk menghindari loop callback dan dependensi siklik yang tidak terbatas. Perubahan akan
hanya diproses dalam frame yang sama jika elemen yang diubah ukurannya berada lebih dalam di DOM
hierarki daripada elemen shallowest yang diproses dalam callback sebelumnya.
Jika tidak, mereka akan ditunda ke {i>frame<i} berikutnya.
Aplikasi
Satu hal yang memungkinkan Anda lakukan ResizeObserver
adalah mengimplementasikan setiap elemen
terhadap kueri media. Dengan mengamati elemen, Anda dapat secara imperatif menentukan
mendesain {i>breakpoint<i} dan
mengubah gaya sebuah elemen. Dalam
example, kotak kedua
akan mengubah radius batas 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 dari atas ke bawah yang biasa adalah pemosisian scroll. Untuk menghindari membingungkan pengguna, akan sangat membantu jika jendela menempel di bagian bawah percakapan, tempat pesan terbaru muncul. Selain itu, segala jenis tata letak perubahan (misalnya ponsel yang beralih dari lanskap ke potret atau sebaliknya) seharusnya mencapai hal yang sama.
ResizeObserver
memungkinkan Anda menulis satu kode yang menangani
kedua skenario. Mengubah ukuran jendela adalah peristiwa yang dapat dilakukan oleh ResizeObserver
tangkap menurut definisi, tetapi memanggil appendChild()
juga akan mengubah ukuran elemen tersebut
(kecuali overflow: hidden
disetel), karena perlu memberikan ruang untuk file baru
yang kurang penting. Dengan mengingat hal ini, dibutuhkan sangat sedikit
baris untuk mencapai tujuan yang
efek:
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, kan?
Dari sini, saya dapat menambahkan lebih banyak kode untuk menangani kasus di mana pengguna menggulir secara manual dan ingin men-scroll untuk menempelkan pesan tersebut saat pesan baru akan diperlukan.
Kasus penggunaan lainnya adalah untuk segala jenis elemen kustom yang melakukan tata letak sendiri.
Hingga ResizeObserver
, tidak ada cara yang dapat diandalkan untuk mendapatkan notifikasi saat
dimensi berubah sehingga turunannya dapat ditata lagi.
Efek pada Interaksi dengan Gambar Berikutnya (INP)
Interaction to Next Paint (INP) adalah metrik yang mengukur responsivitas halaman secara keseluruhan terhadap interaksi pengguna. Jika INP halaman ada dalam “bagus” nilai minimum—yaitu, 200 dalam milidetik atau kurang—dapat dikatakan bahwa sebuah laman dapat responsif terhadap interaksi pengguna dengannya.
Sementara jumlah waktu yang dibutuhkan callback peristiwa untuk berjalan sebagai respons terhadap interaksi pengguna dapat berkontribusi signifikan terhadap total latensi interaksi, aspek ini bukan satu-satunya aspek INP yang perlu dipertimbangkan. INP juga mempertimbangkan jumlah waktu yang diperlukan untuk pelukisan berikutnya dari interaksi. Ini adalah jumlah waktu yang dibutuhkan untuk pekerjaan rendering yang diperlukan untuk memperbarui pengguna sebagai respons terhadap interaksi yang akan diselesaikan.
Jika ResizeObserver
diperhatikan, hal ini penting karena callback yang
instance ResizerObserver
yang berjalan terjadi tepat sebelum pekerjaan rendering. Ini
memang didesain, karena pekerjaan yang terjadi di callback harus dilakukan
karenanya, kemungkinan besar tindakan tersebut akan memerlukan perubahan
API melalui antarmuka pengguna grafis.
Lakukan tugas rendering sesedikit yang diperlukan dalam ResizeObserver
, karena proses rendering yang berlebihan dapat menimbulkan situasi ketika browser
terlambat dalam melakukan
pekerjaan penting. Misalnya, jika ada interaksi yang
yang menyebabkan callback ResizeObserver
berjalan, pastikan Anda melakukan
berikut untuk memfasilitasi pengalaman yang selancar mungkin:
- Pastikan pemilih CSS Anda sesederhana mungkin untuk menghindari penghitungan ulang gaya yang berlebihan. Penghitungan ulang gaya terjadi sebelum tata letak, dan pemilih CSS yang kompleks bisa menunda operasi tata letak.
- Hindari melakukan tugas apa pun di callback
ResizeObserver
yang dapat memicu mengubah posisi/geometri secara paksa. - Waktu yang dibutuhkan untuk memperbarui tata letak laman biasanya bertambah seiring dengan
jumlah elemen DOM di suatu halaman. Meski hal ini berlaku, apakah halaman menggunakan
ResizeObserver
, pekerjaan yang dilakukan di callbackResizeObserver
dapat menjadi signifikan seiring dengan meningkatnya kompleksitas struktural halaman.
Kesimpulan
ResizeObserver
tersedia di semua besar
browser
dan menyediakan cara yang efisien untuk memantau
perubahan ukuran elemen pada satu elemen
level organisasi. Berhati-hatilah untuk tidak menunda rendering terlalu banyak dengan API canggih ini.