पेश है विज़ुअलव्यूपोर्ट

अगर हम आपको बताएं कि एक से ज़्यादा व्यूपोर्ट हैं, तो क्या होगा.

BRRRRAAAAAAAMMMMMMMMMM

फ़िलहाल, जिस व्यूपोर्ट का इस्तेमाल किया जा रहा है वह असल में एक व्यूपोर्ट में मौजूद व्यूपोर्ट है.

BRRRRAAAAAAAMMMMMMMMMM

कभी-कभी, डीओएम से मिलने वाला डेटा, उनमें से किसी एक व्यूपोर्ट का होता है, न कि दूसरे का.

BRRRRAAAAM… रुकिए, क्या?

यह सच है, इस पर एक नज़र डालें:

लेआउट व्यूपोर्ट बनाम विज़ुअल व्यूपोर्ट

ऊपर दिए गए वीडियो में, एक वेब पेज को स्क्रोल और पिंच-ज़ूम किया जा रहा है. साथ ही, दाईं ओर एक मिनी-मैप भी दिख रहा है, जिसमें पेज में व्यूपोर्ट की पोज़िशन दिख रही है.

सामान्य स्क्रोलिंग के दौरान, चीज़ें आसानी से हो जाती हैं. हरे रंग का यह हिस्सा, लेआउट व्यूपोर्ट को दिखाता है. position: fixed आइटम इसी पर चिपकते हैं.

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

अन्य डिवाइसों के साथ काम करने की क्षमता को बेहतर बनाना

माफ़ करें, वेब एपीआई, जिस व्यूपोर्ट का रेफ़रंस देते हैं उसमें अंतर होता है. साथ ही, वे सभी ब्राउज़र में एक जैसे नहीं होते.

उदाहरण के लिए, element.getBoundingClientRect().y, लेआउट व्यूपोर्ट में मौजूद ऑफ़सेट दिखाता है. यह अच्छा है, लेकिन अक्सर हमें पेज पर मौजूद जगह की जानकारी चाहिए. इसलिए, हम यह लिखते हैं:

element.getBoundingClientRect().y + window.scrollY

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

Chrome 61 में, window.scrollY को लेआउट व्यूपोर्ट के तौर पर इस्तेमाल किया जाता है. इसका मतलब है कि ऊपर दिया गया कोड, पिंच-ज़ूम करने पर भी काम करता है. असल में, ब्राउज़र धीरे-धीरे सभी पोज़िशनल प्रॉपर्टी को बदल रहे हैं, ताकि वे लेआउट व्यूपोर्ट का रेफ़रंस दे सकें.

हालांकि, एक नई प्रॉपर्टी के लिए ऐसा नहीं किया जा सकता…

स्क्रिप्ट को विज़ुअल व्यूपोर्ट दिखाना

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

console.log(window.visualViewport.width);

window.visualViewport से हमें ये जानकारी मिलती है:

visualViewport प्रॉपर्टी
offsetLeft सीएसएस पिक्सल में, विज़ुअल व्यूपोर्ट के बाएं किनारे और लेआउट व्यूपोर्ट के बीच की दूरी.
offsetTop सीएसएस पिक्सल में, विज़ुअल व्यूपोर्ट के ऊपरी किनारे और लेआउट व्यूपोर्ट के बीच की दूरी.
pageLeft सीएसएस पिक्सल में, विज़ुअल व्यूपोर्ट के बाएं किनारे और दस्तावेज़ की बाईं सीमांत के बीच की दूरी.
pageTop सीएसएस पिक्सल में, विज़ुअल व्यूपोर्ट के ऊपरी किनारे और दस्तावेज़ की ऊपरी सीमा के बीच की दूरी.
width सीएसएस पिक्सल में, विज़ुअल व्यूपोर्ट की चौड़ाई.
height सीएसएस पिक्सल में, विज़ुअल व्यूपोर्ट की ऊंचाई.
scale पिंच करके ज़ूम करने पर लागू होने वाला स्केल. अगर ज़ूम करने की वजह से कॉन्टेंट का साइज़ दोगुना हो जाता है, तो यह 2 दिखाएगा. इस पर devicePixelRatio का असर नहीं पड़ता.

कुछ इवेंट भी हैं:

window.visualViewport.addEventListener('resize', listener);
visualViewport इवेंट
resize width, height या scale में बदलाव होने पर ट्रिगर होता है.
scroll offsetLeft या offsetTop में बदलाव होने पर ट्रिगर होता है.

डेमो

इस लेख की शुरुआत में दिया गया वीडियो, visualViewport का इस्तेमाल करके बनाया गया है. इसे Chrome 61 और उसके बाद के वर्शन में देखें. इसमें visualViewport का इस्तेमाल करके, विज़ुअल व्यूपोर्ट के सबसे ऊपर दाईं ओर मिनी-मैप को चिपकाया गया है. साथ ही, इन्वर्स स्केल लागू किया गया है, ताकि पिंच-ज़ूम करने के बावजूद, यह हमेशा एक ही साइज़ में दिखे.

ध्यान देने वाली बातें

इवेंट सिर्फ़ तब ट्रिगर होते हैं, जब विज़ुअल व्यूपोर्ट में बदलाव होता है

यह बताना ज़रूरी नहीं है, लेकिन जब मैंने पहली बार visualViewport के साथ काम किया, तो मुझे यह पता चला.

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

असल समस्या स्क्रोल करने में है. अगर स्क्रोल करने पर भी लेआउट व्यूपोर्ट के हिसाब से विज़ुअल व्यूपोर्ट स्टैटिक रहता है, तो आपको visualViewport पर scroll इवेंट नहीं मिलता. ऐसा आम तौर पर होता है. दस्तावेज़ को सामान्य तौर पर स्क्रोल करने के दौरान, विज़ुअल व्यूपोर्ट, लेआउट व्यूपोर्ट के सबसे ऊपर बाईं ओर लॉक रहता है. इसलिए, visualViewport पर scroll ट्रिगर नहीं होता.

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

visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
window.addEventListener('scroll', update);

एक से ज़्यादा दर्शकों के लिए, एक ही वीडियो को दोबारा अपलोड करने से बचना

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

// Add listeners
visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
addEventListener('scroll', update);

let pendingUpdate = false;

function update() {
    // If we're already going to handle an update, return
    if (pendingUpdate) return;

    pendingUpdate = true;

    // Use requestAnimationFrame so the update happens before next render
    requestAnimationFrame(() => {
    pendingUpdate = false;

    // Handle update here
    });
}

मैंने इस बारे में एक समस्या दर्ज की है, क्योंकि मुझे लगता है कि इसके लिए कोई बेहतर तरीका हो सकता है. जैसे, एक update इवेंट.

इवेंट हैंडलर काम नहीं करते

Chrome में मौजूद किसी गड़बड़ी की वजह से, यह काम नहीं करता:

यह न करें

गड़बड़ी वाला – इवेंट हैंडलर का इस्तेमाल करता है

visualViewport.onscroll = () => console.log('scroll!');

इसके बजाय:

यह करें

काम करता है – इवेंट लिसनर का इस्तेमाल करता है

visualViewport.addEventListener('scroll', () => console.log('scroll'));

ऑफ़सेट वैल्यू को राउंड किया जाता है

मुझे लगता है (मुझे उम्मीद है) कि यह Chrome का एक और गड़बड़ी है.

offsetLeft और offsetTop को राउंड किया जाता है. इसलिए, जब उपयोगकर्ता ज़ूम इन करता है, तो यह वैल्यू बहुत गलत हो जाती है. डेमो के दौरान, इसकी समस्याएं देखी जा सकती हैं – अगर उपयोगकर्ता ज़ूम इन करता है और धीरे-धीरे पैन करता है, तो मिनी-मैप, ज़ूम न किए गए पिक्सल के बीच स्नैप करता है.

इवेंट रेट धीमा है

अन्य resize और scroll इवेंट की तरह, ये हर फ़्रेम में ट्रिगर नहीं होते, खास तौर पर मोबाइल पर. डेमो के दौरान, यह देखा जा सकता है – पिंच करके ज़ूम करने के बाद, मिनी-मैप को व्यूपोर्ट पर लॉक रखने में समस्या आती है.

सुलभता

डेमो में, मैंने उपयोगकर्ता के पिंच-ज़ूम को रोकने के लिए visualViewport का इस्तेमाल किया. इस खास डेमो के लिए यह सही है, लेकिन ऐसा कोई भी काम करने से पहले आपको ध्यान से सोचना चाहिए जिससे उपयोगकर्ता की ज़ूम इन करने की इच्छा को बदला जा सके.

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

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

visualViewport.addEventListener('resize', () => {
    if (visualViewport.scale > 1) {
    // Post data to analytics service
    }
});

यह बहुत आसान है! visualViewport एक अच्छा छोटा एपीआई है, जो काम करने के दौरान, काम करने से जुड़ी समस्याओं को हल करता है.