परफ़ॉर्मेंट पैरालैक्सिंग

पॉल लुईस
रॉबर्ट फ़्लैक
रॉबर्ट फ़्लैक

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

पैरालैक्स इलस्ट्रेशन.

बहुत ज़्यादा शब्द हैं, पढ़ा नहीं गया

  • पैरालैक्स ऐनिमेशन बनाने के लिए, स्क्रोल इवेंट या background-position का इस्तेमाल न करें.
  • ज़्यादा सटीक पैरालैक्स इफ़ेक्ट बनाने के लिए, सीएसएस 3D ट्रांसफ़ॉर्म का इस्तेमाल करें.
  • मोबाइल Safari के लिए position: sticky का इस्तेमाल करें, ताकि यह पक्का किया जा सके कि पैरालैक्स इफ़ेक्ट लागू हो.

अगर आपको ड्रॉप-इन सलूशन चाहिए, तो यूज़र इंटरफ़ेस (यूआई) के सैंपल GitHub रेपो पर जाएं और Parallax हेल्पर JS को लें! आप GitHub के रेपो में पैरालैक्स स्क्रोलर का लाइव डेमो देख सकते हैं.

समस्या की जानकारी देने वाले पैरालैक्सर

सबसे पहले, पैरलैक्स इफ़ेक्ट हासिल करने के दो सामान्य तरीकों पर बात करते हैं. खास तौर पर, हम समझते हैं कि वे हमारे मकसद के लिए सही क्यों नहीं हैं.

खराब: स्क्रोल इवेंट का इस्तेमाल किया जा रहा है

पैरालैक्सिंग के लिए ज़रूरी है कि इसे स्क्रोल-कप किया गया हो; पेज के स्क्रोल की स्थिति में किए गए हर एक बदलाव के लिए, पैरालैक्सिंग एलिमेंट की रैंक अपडेट होनी चाहिए. यह आसान लगता है, लेकिन मॉडर्न ब्राउज़र की एक अहम प्रोसेस, एसिंक्रोनस तरीके से काम करने की उनकी क्षमता है. यह हमारे खास मामले में, इवेंट स्क्रोल करने पर लागू होता है. ज़्यादातर ब्राउज़र में, स्क्रोल इवेंट को "सबसे बेहतर" के तौर पर डिलीवर किया जाता है. साथ ही, यह ज़रूरी नहीं है कि वह स्क्रोल ऐनिमेशन के हर फ़्रेम पर दिखे!

इस ज़रूरी जानकारी से हमें यह पता चलता है कि हमें JavaScript पर आधारित ऐसे समाधान का इस्तेमाल क्यों नहीं करना चाहिए जो स्क्रोल इवेंट के आधार पर एलिमेंट को एक जगह से दूसरी जगह ले जाता हो: JavaScript इस बात की गारंटी नहीं देता है कि पेज के स्क्रोल की पोज़िशन के हिसाब से, पैरालैक्सिंग काम करती रहेगी. Mobile Safari के पुराने वर्शन में, स्क्रोल इवेंट असल में स्क्रोल के आखिर में डिलीवर किए जाते थे. इससे JavaScript पर आधारित स्क्रोल इफ़ेक्ट बनाना नामुमकिन हो गया था. हाल के वर्शन, ऐनिमेशन के दौरान स्क्रोल इवेंट करते हैं, लेकिन Chrome की तरह ही, यह "सबसे अच्छी कोशिश" के आधार पर होता है. अगर मुख्य थ्रेड किसी दूसरे काम में व्यस्त है, तो स्क्रोल इवेंट तुरंत डिलीवर नहीं होंगे. इसका मतलब है कि पैरालैक्स इफ़ेक्ट हट जाएगा.

खराब है: background-position को अपडेट किया जा रहा है

एक और स्थिति जिससे हम बचना चाहते हैं, वह है हर फ़्रेम पर पेंटिंग करना. कई समाधान, पैरालैक्स लुक देने के लिए background-position को बदलने की कोशिश करते हैं. इससे, ब्राउज़र स्क्रोल करने पर पेज के उन हिस्सों को फिर से पेंट करता है जिन पर असर पड़ा है. यह ऐनिमेशन को जैंक करने के लिए काफ़ी महंगा हो सकता है.

अगर हम पैरालैक्स मोशन के प्रॉमिस को पूरा करना चाहते हैं, तो हम कुछ ऐसा चाहते हैं जिसे एक्सेलरेटेड प्रॉपर्टी के तौर पर लागू किया जा सके. इसका मतलब है कि बदलाव और ओपैसिटी को बनाए रखा जा सकता है. साथ ही, यह स्क्रोल इवेंट पर निर्भर नहीं होना चाहिए.

3D में सीएसएस

स्कॉट केलम और कीथ क्लार्क, दोनों ने पैरालैक्स मोशन पाने के लिए सीएसएस 3D का इस्तेमाल करने में अहम योगदान दिया है.

  • overflow-y: scroll की मदद से स्क्रोल करने के लिए, कंटेनिंग एलिमेंट सेट अप करें (शायद overflow-x: hidden).
  • उसी एलिमेंट के लिए, perspective वैल्यू और top left या 0 0 पर सेट perspective-origin लागू करें.
  • उस एलिमेंट के बच्चों के लिए, Z में अनुवाद लागू करें और उनका बैक अप लें, ताकि वे स्क्रीन पर उनके साइज़ पर असर डाले बिना पैरलेक्स मोशन दे पाएं.

इस तरीके के लिए सीएसएस ऐसा दिखता है:

.container {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: scroll;
  perspective: 1px;
  perspective-origin: 0 0;
}

.parallax-child {
  transform-origin: 0 0;
  transform: translateZ(-2px) scale(3);
}

यहां इस तरह के एचटीएमएल का स्निपेट माना जाता है:

<div class="container">
    <div class="parallax-child"></div>
</div>

पर्सपेक्टिव के हिसाब से स्केल को अडजस्ट करना

चाइल्ड एलिमेंट को वापस पुश करने पर, वह उस वैल्यू के अनुपात में कम हो जाएगा जिस पर वह देखे जा सकेंगे. इस समीकरण की मदद से यह हिसाब लगाया जा सकता है कि इसे कितना स्केल करने की ज़रूरत है: (नज़रिये - दूरी) / नज़रिए. हम काफ़ी हद तक चाहते हैं कि पैरालैक्सिंग एलिमेंट को पैरलेक्स पर सेट किया जाए, लेकिन उसे उस साइज़ में दिखाया जाए जैसा हमने उसे लिखा है. इसलिए, उसे इस तरह बढ़ाने की ज़रूरत है न कि उसे पहले जैसा रखें.

ऊपर दिए गए कोड के मामले में, ऐंगल 1px है और parallax-child की Z दूरी -2px है. इसका मतलब है कि एलिमेंट को 3x तक स्केल करना होगा. इसमें कोड में प्लग की गई वैल्यू दिखती है: scale(3).

किसी भी कॉन्टेंट में translateZ वैल्यू लागू नहीं की गई है, तो ऐसी वैल्यू को शून्य से बदला जा सकता है. इसका मतलब है कि स्केल (प्रतिस्पेक्टिव - 0) / परस्पेक्टिव है, जो 1 की वैल्यू पर निकाला जाता है. इसका मतलब है कि स्केल को न तो बढ़ाया या घटाया गया है. वाकई आसान.

यह तरीका कैसे काम करता है

यह समझना ज़रूरी है कि यह तरीका क्यों कारगर है, क्योंकि हम इस जानकारी का इस्तेमाल जल्द ही करेंगे. स्क्रोल करना एक ट्रांसफ़ॉर्म है. इसलिए, इसे तेज़ किया जा सकता है. इसमें ज़्यादातर लेयर को जीपीयू के साथ शिफ़्ट करना होता है. एक सामान्य स्क्रोल में, स्क्रोल करने की प्रोसेस 1:1 तरीके से होती है. स्क्रोलिंग एलिमेंट और इसके चाइल्ड एलिमेंट की तुलना 1:1 तरीके से होती है. अगर किसी एलिमेंट को 300px तक स्क्रोल किया जाता है, तो उसके चाइल्ड एलिमेंट उसके बराबर हो जाते हैं: 300px.

हालांकि, स्क्रोलिंग एलिमेंट पर एक पर्सपेक्टिव वैल्यू लागू करने से, इस प्रोसेस में गड़बड़ी हो जाती है. इससे स्क्रोल ट्रांसफ़ॉर्म को अंडरलाइन करने वाले मैट्रिक्स बदल जाते हैं. अब 300 पिक्सल का स्क्रोल करने पर बच्चे सिर्फ़ 150 पिक्सल तक बढ़ सकते हैं. हालांकि, यह आपकी चुनी गई perspective और translateZ वैल्यू पर निर्भर करता है. अगर किसी एलिमेंट की translateZ वैल्यू 0 है, तो उस एलिमेंट को 1:1 पर स्क्रोल किया जाएगा (पहले की तरह). कुल नतीजा: पैरालैक्स मोशन. सबसे ज़रूरी बात यह है कि इसे ब्राउज़र की अंदरूनी स्क्रोल मशीन के हिस्से के तौर पर अपने-आप मैनेज किया जाता है. इसका मतलब है कि आपको scroll इवेंट सुनने या background-position बदलने की ज़रूरत नहीं है.

ऑइंटमेंट में मक्खी: मोबाइल सफ़ारी

हर इफ़ेक्ट के लिए कुछ सावधानियां हैं. बदलाव करने के लिए एक ज़रूरी चीज़, चाइल्ड एलिमेंट में 3D इफ़ेक्ट को सुरक्षित रखना है. अगर पर्सपेक्टिव और उसके पैरालैक्सिंग चाइल्ड एलिमेंट के बीच हैरारकी में कोई एलिमेंट मौजूद है, तो 3D पर्सनैल "फ़्लैट किया गया" होता है. इसका मतलब है कि एलिमेंट मौजूद नहीं है.

<div class="container">
    <div class="parallax-container">
    <div class="parallax-child"></div>
    </div>
</div>

ऊपर दिए गए एचटीएमएल में, .parallax-container नया है. यह perspective की वैल्यू को असरदार तरीके से फ़्लैट कर देगा और हम पैरलैक्स इफ़ेक्ट खो देंगे. ज़्यादातर मामलों में, समाधान काफ़ी आसान है: आपको एलिमेंट में transform-style: preserve-3d जोड़ना होगा, जिससे यह ऐसे किसी भी 3D इफ़ेक्ट (जैसे कि हमारा पर्सपेक्टिव वैल्यू) का इस्तेमाल कर सकेगा जो ट्री पर लागू किया गया था.

.parallax-container {
  transform-style: preserve-3d;
}

हालांकि, Mobile Safari के मामले में चीज़ें थोड़ी ज़्यादा जटिल होती हैं. कंटेनर एलिमेंट में overflow-y: scroll को लागू करने की सुविधा तकनीकी रूप से काम करती है. हालांकि, इससे बचने के लिए, स्क्रोल करने वाले एलिमेंट को फ़्लिंग करना पड़ता है. इसे -webkit-overflow-scrolling: touch को जोड़ना है, लेकिन इससे perspective भी फ़्लैट हो जाएगा और हमें कोई पैरालैक्सिंग नहीं मिलेगी.

बेहतर बनाने की प्रोसेस को बेहतर बनाने के लिहाज़ से, शायद यह कोई समस्या नहीं है. अगर हम हर स्थिति में पैरालैक्स नहीं कर सकते, तब भी हमारा ऐप्लिकेशन काम करेगा. हालांकि, इसका समाधान निकालना हमारे लिए अच्छा होगा.

बचाव के लिए position: sticky!

असल में, position: sticky के रूप में कुछ मदद है. इससे स्क्रोल के दौरान, एलिमेंट को व्यूपोर्ट या किसी पैरंट एलिमेंट के सबसे ऊपर "बनाया" जा सकता है. ज़्यादातर चीज़ों की खास जानकारी काफ़ी जटिल होती है, लेकिन इसमें एक छोटा सा जेम भी है जो बहुत काम आता है:

पहली नज़र में शायद इसका ज़्यादा फ़ायदा न मिले, लेकिन इस वाक्य में एक अहम बात यह है कि किसी एलिमेंट के स्टिकीनेस का हिसाब कैसे लगाया जाता है: " ऑफ़सेट का हिसाब, स्क्रोलिंग बॉक्स से सबसे नज़दीकी पूर्वज के रेफ़रंस से लगाया जाता है". दूसरे शब्दों में, स्टिकी एलिमेंट को एक जगह से दूसरी जगह ले जाने की दूरी (यह किसी दूसरे एलिमेंट या व्यूपोर्ट से अटैच हो सके, इसके लिए तय की जाती है) किसी भी दूसरे ट्रांसफ़ॉर्मेशन को लागू करने से पहले इसका हिसाब लगाया जाता है, न कि बाद में. इसका मतलब है कि, काफ़ी पहले स्क्रोल करने वाले उदाहरण की तरह, अगर ऑफ़सेट की गिनती 300 पिक्सल की गई होती है, तो 300 पिक्सल ऑफ़सेट वैल्यू को किसी भी स्टिकी एलिमेंट पर लागू करने से पहले बदलने के लिए, ऐंगल (या किसी भी अन्य ट्रांसफ़ॉर्म) का इस्तेमाल करने का नया मौका होता है.

position: -webkit-sticky को पैरालैक्सिंग एलिमेंट पर लागू करने से, हम -webkit-overflow-scrolling: touch के फ़्लैट करने के असर को असरदार तरीके से "रिवर्स" कर सकते हैं. इससे यह पक्का होता है कि पैरालैक्सिंग एलिमेंट, स्क्रोलिंग बॉक्स से सबसे नज़दीकी पूर्वज का रेफ़रंस देता है, जो इस मामले में .container है. फिर, पहले की तरह ही, .parallax-container perspective वैल्यू लागू करता है, जो कैलकुलेट किए गए स्क्रोल ऑफ़सेट में बदलाव करता है और एक पैरलैक्स इफ़ेक्ट बनाता है.

<div class="container">
    <div class="parallax-container">
    <div class="parallax-child"></div>
    </div>
</div>
.container {
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

.parallax-container {
  perspective: 1px;
}

.parallax-child {
  position: -webkit-sticky;
  top: 0px;
  transform: translate(-2px) scale(3);
}

इससे Mobile Safari के लिए पैरलैक्स इफ़ेक्ट फिर से शुरू हो जाता है, जो कि हर तरह से शानदार समाचार है!

स्टिकी पोज़िशनिंग चेतावनियां

यहां अंतर है. हालांकि: position: sticky पैरालैक्स मैकेनिक्स में बदलाव करता है. स्टिकी पोज़िशनिंग की मदद से, एलिमेंट को स्क्रोलिंग कंटेनर में चिपकाने की कोशिश की जाती है, जबकि नॉन-स्टिकी वर्शन में ऐसा नहीं होता. इसका मतलब यह है कि स्टिकी वाला पैरालैक्स, बिना इस वाले पैरालैक्स के उलट होता है:

  • position: sticky के साथ, एलिमेंट के पास z=0 होगा, जिससे वह कम हो जाएगा.
  • position: sticky के बिना, z=0 के जितना पास होगा, वह ज़्यादा दिखेगा.

अगर आपको यह जानकारी थोड़ी-बहुत मिलती है, तो रॉबर्ट फ़्लैक का यह डेमो देखें. इसमें बताया गया है कि एलिमेंट, स्टिकी पोज़िशन के साथ अलग-अलग तरह से कैसे काम करते हैं. अंतर देखने के लिए, आपको Chrome कैनरी (जो लिखे जाने के समय वर्शन 56 है) या Safari की ज़रूरत होगी.

Parallax के व्यू का स्क्रीनशॉट

रॉबर्ट फ़्लैक का डेमो, जिसमें दिखाया गया है कि position: sticky, पैरालैक्स स्क्रोलिंग पर कैसे असर डालता है.

अलग-अलग गड़बड़ियां और उन्हें ठीक करने के तरीके

हालांकि, किसी भी चीज़ की तरह, अब भी गांठें और उठे हुए हैं, जिन्हें ठीक करने की ज़रूरत है:

  • एक ही तरह के सहायता पर लगातार काम नहीं करता. Chrome में अब भी सहायता लागू की जा रही है, Edge पूरी तरह से काम नहीं करता है, और Firefox में पेंटिंग की गड़बड़ियां हैं, जब स्टिकी को पर्सपेक्टिव ट्रांसफ़ॉर्म के साथ मिलाया जाता है. ऐसे मामलों में, सिर्फ़ ज़रूरी होने पर position: sticky (-webkit- प्रीफ़िक्स वाला वर्शन) को जोड़ने के लिए, छोटा कोड जोड़ना बेहतर होता है. यह कोड सिर्फ़ मोबाइल Safari के लिए है.
  • यह इफ़ेक्ट, Edge में "सिर्फ़ काम करने" के लिए नहीं है. Edge, ओएस लेवल पर स्क्रोलिंग को हैंडल करने की कोशिश करता है, जो आम तौर पर अच्छी बात होती है, लेकिन इस स्थिति में यह स्क्रोल के दौरान स्क्रीन में हुए बदलावों का पता लगाने से रोकता है. इसे ठीक करने के लिए, एक तय पोज़िशन एलिमेंट को जोड़ा जा सकता है. ऐसा करने से एज को नॉन-ओएस स्क्रोलिंग तरीके पर स्विच किया जा सकता है. इससे यह पक्का हो जाता है कि तरीके में बदलाव हो.
  • "पेज का कॉन्टेंट बहुत बड़ा हो गया है!" कई ब्राउज़र, पेज का कॉन्टेंट बड़ा होने के लिए स्केल को ध्यान में रखते हैं, लेकिन अफ़सोस की बात यह है कि Chrome और Safari नज़रिए को शामिल नहीं करते. इसलिए, अगर मौजूद है - जैसे कि - किसी एलिमेंट पर 3x का स्केल लागू किया गया है, तो आपको स्क्रोल बार और मिलते-जुलते नतीजे दिखेंगे. भले ही, perspective लागू करने के बाद वह एलिमेंट 1x पर हो. इस समस्या को हल करने के लिए, सबसे नीचे दाएं कोने में मौजूद एलिमेंट (transform-origin: bottom right के साथ) को स्केल करें. ऐसा इसलिए, क्योंकि इससे बड़े साइज़ के एलिमेंट, स्क्रोल किए जा सकने वाले एरिया के "नेगेटिव रीजन" (आम तौर पर, सबसे ऊपर बाईं ओर) में बढ़ जाएंगे. स्क्रोल किए जा सकने वाले क्षेत्रों में, कभी भी नेगेटिव रीजन में मौजूद कॉन्टेंट को देखा या उस पर स्क्रोल नहीं किया जा सकता.

नतीजा

सोच-समझकर इस्तेमाल करने पर पैरालैक्सिंग एक मज़ेदार इफ़ेक्ट है. जैसा कि देखा जा सकता है, इसे परफ़ॉर्म करने वाले, स्क्रोल के साथ जोड़े जाने वाले, और क्रॉस-ब्राउज़र वाले तरीकों से लागू किया जा सकता है. इसमें थोड़ा-बहुत गणित के सवाल और कुछ हद तक बॉयलरप्लेट की ज़रूरत होती है, ताकि आपको मनमुताबिक नतीजा मिल सके. इसलिए, हमने एक छोटी हेल्पर लाइब्रेरी और सैंपल इकट्ठा किया है. आपको यह जानकारी यूआई एलिमेंट सैंपल GitHub रेपो में मिल जाएगी.

अभी खेलें और हमें बताएं कि आपका कॉन्टेंट कैसा है.