Resize ऑब्ज़र्वर: यह एलिमेंट के लिए, document.onresize की तरह काम करता है

ResizeObserver से आपको किसी एलिमेंट के साइज़ में बदलाव होने की जानकारी मिलती है.

जो मेडली
जो मेडली
जेरेमी वैगनर
जेरेमी वैगनर

व्यूपोर्ट के डाइमेंशन में हुए किसी भी बदलाव के बारे में सूचना पाने के लिए, आपको ResizeObserver से पहले दस्तावेज़ के resize इवेंट में एक लिसनर को जोड़ना पड़ता था. इसके बाद, इवेंट हैंडलर में आपको यह पता लगाना होगा कि इस बदलाव से कौनसे एलिमेंट पर असर पड़ा है. साथ ही, सही तरीके से प्रतिक्रिया देने के लिए, किसी रूटीन को कॉल करना होगा. अगर आपको साइज़ बदलने के बाद, किसी एलिमेंट के नए डाइमेंशन की ज़रूरत पड़ती है, तो आपको getBoundingClientRect() या getComputedStyle() को कॉल करना होगा. अगर आपने अपने सभी और सभी लेखों के बैच बनाने पर ध्यान नहीं दिया, तो इसकी वजह से लेआउट थ्रेशिंग हो सकती है.

इसमें ऐसे मामले भी शामिल नहीं थे जहां एलिमेंट का साइज़, मुख्य विंडो का साइज़ बदले बिना ही बदला जाता है. उदाहरण के लिए, नए चाइल्ड जोड़ने, एलिमेंट की display स्टाइल को none पर सेट करने या इससे मिलती-जुलती कार्रवाइयों से एलिमेंट का साइज़, उसके प्रतिरूप या उसके पूर्वजों का साइज़ बदल सकता है.

इस वजह से, ResizeObserver एक उपयोगी प्रिमिटिव है. यह किसी भी मॉनिटर किए गए एलिमेंट के साइज़ में हुए बदलाव पर प्रतिक्रिया देता है, चाहे वह बदलाव क्यों हुआ हो. इससे, मॉनिटर किए गए एलिमेंट के नए साइज़ को भी ऐक्सेस किया जा सकता है.

ब्राउज़र सहायता

  • 64
  • 79
  • 69
  • 78 जीबी में से

सोर्स

API

ऊपर बताए गए Observer सफ़िक्स वाले सभी एपीआई का एपीआई डिज़ाइन आसान है. ResizeObserver भी अपवाद नहीं है. इसके लिए, ResizeObserver ऑब्जेक्ट बनाया जाता है और कंस्ट्रक्टर को कॉलबैक पास किया जाता है. कॉलबैक ResizeObserverEntry ऑब्जेक्ट की एक कलेक्शन पास करता है. हर मॉनिटर किए गए एलिमेंट के लिए एक एंट्री—इसमें एलिमेंट के लिए नए डाइमेंशन शामिल होते हैं.

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);

कुछ जानकारी

किस चीज़ की शिकायत की जा रही है?

आम तौर पर, ResizeObserverEntry contentRect नाम की प्रॉपर्टी के ज़रिए, किसी एलिमेंट के कॉन्टेंट बॉक्स को रिपोर्ट करता है, जो DOMRectReadOnly ऑब्जेक्ट दिखाता है. कॉन्टेंट बॉक्स वह बॉक्स होता है जिसमें कॉन्टेंट को रखा जा सकता है. यह बॉर्डर बॉक्स होता है, जिसमें से पैडिंग (जगह) घटाई जाती है.

सीएसएस बॉक्स मॉडल का डायग्राम.

ध्यान रखें कि ResizeObserver, contentRect और पैडिंग, दोनों के डाइमेंशन को रिपोर्ट करता है. हालांकि, यह contentRect को सिर्फ़ देखता है. एलिमेंट के बाउंडिंग बॉक्स के साथ contentRect को भ्रमित न करें. बाउंडिंग बॉक्स, जिसे getBoundingClientRect() ने रिपोर्ट किया है, वह बॉक्स है जिसमें पूरा एलिमेंट और उसके डिसेंडेंट शामिल होते हैं. SVG नियम का एक अपवाद है, जहां ResizeObserver, बाउंडिंग बॉक्स के डाइमेंशन की जानकारी देगा.

Chrome 84 से, ResizeObserverEntry में तीन नई प्रॉपर्टी हैं. इनमें ज़्यादा जानकारी देने वाली सुविधा शामिल की गई है. इनमें से हर प्रॉपर्टी एक ResizeObserverSize ऑब्जेक्ट दिखाती है, जिसमें blockSize प्रॉपर्टी और inlineSize प्रॉपर्टी होती है. यह जानकारी उस समय के ऑब्ज़र्व्ड एलिमेंट के बारे में है, जब कॉलबैक को शुरू किया जाता है.

  • borderBoxSize
  • contentBoxSize
  • devicePixelContentBoxSize

ये सभी आइटम, रीड-ओनली अरे दिखाते हैं, क्योंकि आने वाले समय में उम्मीद है कि वे ऐसे एलिमेंट के साथ काम कर सकेंगे जिनमें कई फ़्रैगमेंट होते हैं और जो एक से ज़्यादा कॉलम वाली स्थितियों में होते हैं. फ़िलहाल, इन कलेक्शन में सिर्फ़ एक एलिमेंट शामिल होगा.

इन प्रॉपर्टी के लिए प्लैटफ़ॉर्म पर सहायता सीमित है, लेकिन Firefox पहले ही पहले दो के साथ काम करता है.

इसकी रिपोर्ट कब की जा रही है?

इस शर्त के मुताबिक, ResizeObserver को पेंट करने से पहले और लेआउट के बाद वाले सभी इवेंट के साइज़ को प्रोसेस करना चाहिए. इससे ResizeObserver के कॉलबैक को आपके पेज के लेआउट में बदलाव करने का सबसे अच्छा तरीका माना जाता है. ResizeObserver को प्रोसेस करने की प्रोसेस, लेआउट और पेंट के बीच होती है. इसलिए, ऐसा करने से सिर्फ़ लेआउट अमान्य होगा, पेंट नहीं.

गोचा

आपके मन में यह सवाल आ सकता है: अगर मैं कॉलबैक के अंदर मौजूद मॉनिटर किए गए एलिमेंट के साइज़ को ResizeObserver में बदल दूं, तो क्या होगा? इसका जवाब है: आप तुरंत कॉलबैक पर एक और कॉल ट्रिगर करेंगे. अच्छी बात यह है कि ResizeObserver में इनफ़ाइनाइट कॉलबैक लूप और साइकल डिपेंडेंसी से बचने का तरीका है. बदलाव उसी फ़्रेम में सिर्फ़ तब प्रोसेस किए जाएंगे, जब बदला गया एलिमेंट डीओएम ट्री में ज़्यादा गहरा हो और पिछले कॉलबैक में प्रोसेस किए गए सबसे पुराने एलिमेंट की तुलना में ज़्यादा गहरा हो. ऐसा न करने पर, उन्हें अगले फ़्रेम पर ले जाया जाएगा.

ऐप्लिकेशन

हर एलिमेंट वाली मीडिया क्वेरी लागू करने के लिए, ResizeObserver आपको अनुमति देता है. एलिमेंट पर नज़र रखकर, ज़रूरी तौर पर डिज़ाइन के लिए ब्रेकपॉइंट तय किए जा सकते हैं. साथ ही, एलिमेंट की स्टाइल भी बदली जा सकती हैं. यहां दिए गए उदाहरण में, दूसरा बॉक्स अपनी बॉर्डर के दायरे को उसकी चौड़ाई के हिसाब से बदल देगा.

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)'));

एक और दिलचस्प उदाहरण चैट विंडो है. आम तौर पर, सबसे ऊपर से नीचे की ओर वाले बातचीत लेआउट में, स्क्रोल की पोज़िशनिंग की समस्या होती है. उपयोगकर्ता को उलझन में डालने से बचने के लिए, यह तब मददगार होता है, जब विंडो बातचीत के निचले हिस्से में रहती है, जहां नए मैसेज दिखते हैं. इसके अलावा, लेआउट में होने वाले किसी भी तरह के बदलाव (लैंडस्केप से पोर्ट्रेट मोड में या लैंडस्केप से पोर्ट्रेट मोड में जाने पर या फ़ोन को लैंडस्केप से पोर्ट्रेट मोड में स्विच करने पर) भी ऐसा ही हो सकता है.

ResizeObserver आपको कोड का एक एक हिस्सा लिखने की अनुमति देता है जो दोनों स्थितियों का ध्यान रखता है. विंडो का साइज़ बदलना एक ऐसा इवेंट है जिसे ResizeObserver, परिभाषा के हिसाब से कैप्चर कर सकता है. हालांकि, appendChild() को कॉल करने पर, उस एलिमेंट का साइज़ भी बदल जाता है (जब तक overflow: hidden को सेट नहीं किया जाता), क्योंकि इसे नए एलिमेंट के लिए जगह बनानी होती है. इस बात को ध्यान में रखते हुए, प्रॉडक्ट से जुड़ा मनचाहा इफ़ेक्ट पाने के लिए, बहुत कम लाइनों की ज़रूरत होती है:

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);

बहुत अच्छा, है न?

यहाँ से, मुझे कुछ और कोड जोड़े जा सकते हैं. इससे यह पता चलेगा कि उपयोगकर्ता ने मैन्युअल तौर पर ऊपर की ओर कैसे स्क्रोल किया है और कोई नया मैसेज आने पर, उस मैसेज पर बने रहने के लिए स्क्रोल करना चाहता है.

इस्तेमाल का एक और उदाहरण, ऐसे कस्टम एलिमेंट के लिए है जो अपना लेआउट खुद इस्तेमाल करता है. ResizeObserver तक इसके डाइमेंशन में बदलाव होने पर सूचना पाने का कोई भरोसेमंद तरीका नहीं था, ताकि इसकी मदद से बच्चों को फिर से दिखाया जा सके.

इंटरैक्शन टू नेक्स्ट पेंट पर असर (आईएनपी)

इंटरैक्शन टू नेक्स्ट पेंट (आईएनपी) एक ऐसी मेट्रिक है जो किसी पेज के रिस्पॉन्स में उपयोगकर्ता के इंटरैक्शन का आकलन करती है. अगर किसी पेज का आईएनपी "अच्छा" थ्रेशोल्ड—यानी 200 मिलीसेकंड या उससे कम है—तो कहा जा सकता है कि कोई पेज, उपयोगकर्ता के इंटरैक्शन के हिसाब से भरोसेमंद है.

किसी उपयोगकर्ता के इंटरैक्शन के जवाब में इवेंट कॉलबैक को चलाने में लगने वाला समय, इंटरैक्शन के कुल इंतज़ार के समय में काफ़ी योगदान दे सकता है. हालांकि, आईएनपी के लिए भी यही एक पहलू नहीं है. आईएनपी इस बात पर भी विचार करता है कि इंटरैक्शन के अगले पेंट को शुरू होने में कितना समय लगता है. यह रेंडरिंग के काम में लगने वाला समय है. यह इंटरैक्शन पूरा होने के बाद, यूज़र इंटरफ़ेस को अपडेट करने में लगता है.

ResizeObserver के लिए यह ज़रूरी है, क्योंकि ResizerObserver इंस्टेंस जिस कॉलबैक को चलाया जाता है, वह काम को रेंडर करने से ठीक पहले होता है. ऐसा डिज़ाइन से होता है, क्योंकि कॉलबैक में होने वाले काम को ध्यान में रखना चाहिए. ऐसा करने पर, यूज़र इंटरफ़ेस में बदलाव की ज़रूरत होगी.

इस बात का ध्यान रखें कि ResizeObserver कॉलबैक में, रेंडरिंग से जुड़ा कम से कम काम हो. ऐसा इसलिए, क्योंकि बहुत ज़्यादा रेंडरिंग से ऐसी स्थितियां बन सकती हैं जहां ब्राउज़र को ज़रूरी काम करने में देरी हो. उदाहरण के लिए, अगर किसी इंटरैक्शन में कॉलबैक होता है, जिसकी वजह से ResizeObserver कॉलबैक चलता है, तो पक्का करें कि उपयोगकर्ता को आसान अनुभव देने के लिए, नीचे दिया गया तरीका अपनाया जा रहा हो:

  • पक्का करें कि आपके सीएसएस सिलेक्टर जितना हो सके उतना आसान हों, ताकि स्टाइल को फिर से कैलकुलेट करने की ज़रूरत से बचें. स्टाइल की रीकैलकुलेशन, लेआउट के ठीक पहले की जाती है. साथ ही, जटिल सीएसएस सिलेक्टर की मदद से, लेआउट की कार्रवाइयां की जाने पर देरी हो सकती है.
  • अपने ResizeObserver कॉलबैक में ऐसा कोई भी काम न करें जिससे फ़ोर्स किए गए रीफ़्लो ट्रिगर हो सकते हैं.
  • आम तौर पर, किसी पेज के लेआउट को अपडेट करने में लगने वाला समय, पेज पर डीओएम एलिमेंट की संख्या बढ़ने के साथ-साथ बढ़ता है. यह सच है कि पेज ResizeObserver का इस्तेमाल करते हैं या नहीं, लेकिन ResizeObserver कॉलबैक में किया जाने वाला काम, पेज के स्ट्रक्चर की जटिलता बढ़ने पर अहम हो सकता है.

नतीजा

ResizeObserver, सभी बड़े ब्राउज़र में उपलब्ध है. साथ ही, यह एलिमेंट के लेवल पर एलिमेंट के साइज़ में होने वाले बदलावों को मॉनिटर करने का एक बेहतर तरीका उपलब्ध कराता है. बस इस बात का ध्यान रखें कि इस दमदार एपीआई की मदद से, रेंडर होने में ज़्यादा समय न लगे.