अगर मैं आपको बताऊँ, तो एक से ज़्यादा व्यूपोर्ट हैं.
BRRRRAAAAAAAMMMMMMMM
और जिस व्यूपोर्ट का इस्तेमाल अभी किया जा रहा है, वह असल में व्यूपोर्ट में एक व्यूपोर्ट है.
BRRRRAAAAAAAMMMMMMMM
कभी-कभी, DOM आपको जो डेटा देता है वह उनमें से किसी एक व्यूपोर्ट का इस्तेमाल करता है और दूसरे का नहीं.
BRRRAAAAM... कुछ इंतज़ार करो?
यह सच है, एक नज़र डालें:
लेआउट व्यूपोर्ट बनाम विज़ुअल व्यूपोर्ट
ऊपर दिया गया वीडियो, वेब पेज को स्क्रोल और पिंच-ज़ूम करके दिखाता है. साथ ही, दाईं ओर एक मिनी-मैप भी है जिसमें पेज के अंदर व्यूपोर्ट की जगह दिखती है.
नियमित स्क्रोलिंग के दौरान चीज़ें काफ़ी आसान होती हैं. हरा एरिया, लेआउट व्यूपोर्ट को दिखाता है, जिस पर 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
एक अच्छा एपीआई है. यह साथ काम करने से जुड़ी समस्याओं को हल करता है.