ResizeObserver - alat tangguh baru untuk bekerja dengan kemampuan beradaptasi

Selamat siang teman!

Responsif adalah salah satu standar pengembangan web. Ada sejumlah besar resolusi layar, dan jumlah ini meningkat setiap saat. Kami berusaha untuk mendukung semua ukuran layar yang mungkin dengan tetap menjaga antarmuka pengguna yang ramah. Solusi terbaik untuk masalah ini adalah permintaan media (permintaan media). Tetapi bagaimana dengan komponen web? Pengembangan web modern didasarkan pada komponen, dan kami membutuhkan cara untuk membuatnya responsif. Hari ini saya ingin berbicara tentang API ResizeObserver, yang memungkinkan Anda memantau (mengamati) perubahan ukuran elemen tertentu, dan bukan seluruh viewport, seperti halnya dengan pertanyaan media.

Sedikit sejarah


Sebelumnya, kami hanya memiliki pertanyaan media yang kami miliki - solusi CSS berdasarkan ukuran, jenis dan resolusi layar perangkat media (menurut perangkat media, maksud saya komputer, ponsel, atau tablet). Kueri media cukup fleksibel dan mudah digunakan. Untuk waktu yang lama, permintaan media hanya tersedia dalam CSS, sekarang mereka juga tersedia di JS melalui window.matchMedia (mediaQueryString). Sekarang kita dapat memeriksa dari perangkat mana halaman dilihat, dan juga memantau perubahan ukuran area tampilan (kita berbicara tentang metode MediaQueryList.addListener () - kira-kira.

Kueri Elemen


Yang tidak kami miliki adalah kemampuan untuk memantau ukuran elemen DOM tunggal, dan bukan hanya seluruh viewport. Pengembang telah mengeluh tentang hal ini selama bertahun-tahun. Ini adalah salah satu fitur yang paling dinanti. Pada 2015, bahkan sebuah proposal diajukan - permintaan ukuran kontainer ( Pertanyaan Kontainer ):
Pengembang sering membutuhkan kemampuan untuk mendesain elemen ketika mereka mengubah ukuran wadah induknya, terlepas dari area tampilan. Permintaan ukuran kontainer memberi mereka kesempatan ini. Contoh penggunaan CSS:
.element : layar media (lebar minimum: 30em) {***}
Kedengarannya hebat, tetapi pembuat browser memiliki alasan yang bagus untuk menolak tawaran ini - ketergantungan sirkular (ketika satu ukuran menentukan yang lain, ini mengarah ke loop tak terbatas; lebih lanjut tentang ini dapat ditemukan di sini ). Opsi apa lagi yang ada? Kita dapat menggunakan window.resize (panggilan balik), tetapi ini adalah "kesenangan yang mahal" - panggilan balik akan dipanggil setiap kali suatu peristiwa terjadi, dan kita akan memerlukan banyak perhitungan untuk menentukan bahwa ukuran komponen kita telah benar-benar berubah ...

Mengubah ukuran elemen pemantau menggunakan API ResizeObserver


Temui API ResizeObserver dari Chrome:
API ResizeObserver adalah antarmuka untuk mengubah ukuran elemen pelacakan. Ini adalah semacam analog dari window.resize event untuk suatu elemen.

API ResizeObserver adalah konsep langsung. Itu sudah diterapkan di Chrome, Firefox dan Safari untuk PC. Dukungan seluler kurang mengesankan - hanya Chrome di Android dan Samsung Internet. Sayangnya, polifile lengkap tidak ada. Polyphile yang tersedia mengandung beberapa batasan (misalnya, respons yang lambat terhadap pengubahan ukuran atau kurangnya dukungan untuk transisi yang lancar). Namun, ini seharusnya tidak menghentikan kami dari pengujian API ini. Jadi ayo kita lakukan!

Contoh: mengubah teks saat mengubah ukuran elemen


Bayangkan situasi berikut - teks di dalam elemen harus berubah tergantung pada ukuran elemen. API ResizeObserver menyediakan dua alat - ResizeObserver dan ResizeObserverEntry. ResizeObserver digunakan untuk melacak ukuran item, dan ResizeObserverEntry berisi informasi tentang item yang telah diubah ukurannya.
Kode ini sangat sederhana:

<h1> size </h1>
<h2> boring text </h2>

const ro = new ResizeObserver(entries => {
    for(let entry of entries){
        const width = entry.contentBoxSize
        ? entry.contentBoxSize.inlineSize
        : entry.contentRect.width

        if(entry.target.tagName === 'H1'){
            entry.target.textContent = width < 1000 'small' : 'big'
        }

        if(entry.target.tagName === 'H2' && width < 500){
            entry.target.textContent = `I won't change anymore`
            ro.unobserve(entry.target) //  ,     500px
        }
    }
})

//       
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))

Pertama, buat objek ResizeObserver dan berikan fungsi panggilan balik sebagai parameter:

const resizeObserver = new ResizeObserver((entries, observer) => {
    for(let entry of entries){
        // 
    }
})

Fungsi ini dipanggil setiap kali salah satu elemen yang terkandung dalam ResizeObserverEntries diubah ukurannya. Parameter kedua dari fungsi callback adalah pengamat itu sendiri. Kita dapat menggunakannya, misalnya, untuk menghentikan pelacakan ketika kondisi tertentu terpenuhi.

Callback mendapatkan array dari ResizeObserverEntry. Setiap entri berisi dimensi elemen yang diamati (target).

for(let entry of entries){
    const width = entry.contentBoxSize
    ? entry.contentBoxSize.inlineSize
    : entry.contentRect.width

    if(entry.target.tagName === 'H1'){
        entry.target.textContent = width < 1000 ? 'small' : 'big'
    }
    ...
}

Kami memiliki tiga properti yang menjelaskan ukuran elemen - borderBoxSize, contentBoxSize, dan contentRect. Mereka mewakili model kotak elemen, yang akan kita bicarakan nanti. Sekarang beberapa kata tentang dukungan. Sebagian besar browser mendukung contentRect, namun, tampaknya, properti ini akan usang:
contentRect muncul pada tahap pengembangan awal dari ResizeObserver dan ditambahkan hanya untuk kepentingan kompatibilitas saat ini. Mungkin di masa depan itu akan dianggap usang.


Oleh karena itu, saya akan sangat menyarankan menggunakan contentRect bersama dengan bordeBoxSize dan contentBoxSize. ResizeObserverSize mencakup dua properti: inlineSize dan blockSize, yang dapat diartikan sebagai lebar dan tinggi (asalkan kita bekerja dalam orientasi horizontal teks - mode penulisan: mode penulisan: horizontal).

Pengamatan Elemen


Hal terakhir yang harus dilakukan adalah mulai melacak item. Untuk melakukan ini, kami memanggil ResizeObserver.observe (). Metode ini menambahkan target baru ke daftar item yang diamati. Kami dapat menambahkan ke daftar ini satu atau beberapa elemen sekaligus:

// resizeObserver(target, options)
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))

Parameter kedua adalah "opsional". Sampai saat ini, satu-satunya opsi yang tersedia adalah kotak, yang mendefinisikan model blok. Nilai yang mungkin adalah kotak konten (default), kotak batas, dan kotak konten perangkat pixel (hanya Chrome). Hanya satu model blok yang dapat didefinisikan dalam satu ResizeObserver.

Untuk berhenti memantau, gunakan ResizeObserver.unobserve (target). Untuk berhenti melacak semua elemen, gunakan ResizeObserver.disconnect ().

Model blok


Kotak konten adalah konten blok tanpa bantalan, batas, dan margin. Kotak perbatasan termasuk padding dan border (tanpa margin).



Kotak konten piksel perangkat adalah konten elemen dalam piksel fisik. Saya belum melihat contoh penggunaan model ini, tetapi tampaknya ini mungkin berguna ketika bekerja dengan kanvas. Inilah diskusi menarik tentang topik ini di Github.

Kapan seorang pengamat mengetahui tentang perubahan?


Panggilan balik dipanggil setiap kali elemen target diubah ukurannya. Inilah yang dikatakan oleh spec tentang hal itu:

  • Pengamatan dipicu ketika item yang diamati ditambahkan / dihapus dari DOM.
  • Pengamatan dipicu ketika properti tampilan elemen yang diamati diatur ke tidak ada.
  • Pengamatan tidak bekerja untuk elemen garis "tidak tersubstitusi".
  • Pengamatan tidak bekerja dalam transformasi CSS.
  • , , .. , 0,0.

Menurut paragraf pertama, kita dapat menentukan perubahan dalam wadah induk saat mengganti anak-anaknya. Sebuah contoh yang bagus dari penggunaan API ResizeObserver adalah dengan menggulir ke bawah jendela obrolan saat menambahkan pesan baru. Contohnya bisa dilihat di sini .

Ingat kueri ukuran kontainer yang saya sebutkan sebelumnya? Tentang masalah ketergantungan sirkulernya? Jadi, API ResizeObserver memiliki solusi bawaan untuk mencegah loop berulang "ubah ukuran". Baca tentang ini di sini .

Terima kasih atas perhatian Anda.

Tautan Berguna:

Spesifikasi
MDN
CanIUse
Artikel pertama dari tim pengembangan
Polyfil paling populer

Source: https://habr.com/ru/post/undefined/


All Articles