iOS और Android ऐप्लिकेशन में मौजूद टैब कॉम्पोनेंट की तरह ही टैब कॉम्पोनेंट बनाने के तरीके के बारे में बुनियादी जानकारी.
इस पोस्ट में, मैं वेब के लिए टैब कॉम्पोनेंट बनाने के बारे में अपनी सोच शेयर करना चाहता हूं. यह कॉम्पोनेंट रिस्पॉन्सिव हो, कई डिवाइसों से इनपुट लेने की सुविधा देता हो, और सभी ब्राउज़र पर काम करता हो. डेमो आज़माएं.
अगर आपको वीडियो देखना ज़्यादा पसंद है, तो इस पोस्ट का YouTube वर्शन यहां दिया गया है:
खास जानकारी
टैब, डिज़ाइन सिस्टम का एक सामान्य कॉम्पोनेंट है. हालांकि, यह कई तरह के आकार और फ़ॉर्म में हो सकता है. पहले, <frame>
एलिमेंट पर बनाए गए डेस्कटॉप टैब थे. अब हमारे पास मोबाइल के ऐसे कॉम्पोनेंट हैं जो फ़िज़िक्स की प्रॉपर्टी के आधार पर कॉन्टेंट को ऐनिमेट करते हैं.
इन सभी का मकसद एक ही है: स्टोरेज की जगह बचाना.
आजकल, टैब का इस्तेमाल करने वाले लोगों के लिए, बटन नेविगेशन एरिया बहुत ज़रूरी है. इससे डिसप्ले फ़्रेम में कॉन्टेंट को दिखाया या छिपाया जा सकता है. कई अलग-अलग कॉन्टेंट एरिया एक ही स्पेस शेयर करते हैं. हालांकि, इन्हें नेविगेशन में चुने गए बटन के आधार पर दिखाया जाता है.

वेब रणनीति
कुल मिलाकर, मुझे इस कॉम्पोनेंट को बनाने में काफ़ी आसानी हुई. इसके लिए, मैं वेब प्लैटफ़ॉर्म की कुछ ज़रूरी सुविधाओं का शुक्रिया अदा करना चाहूंगा:
scroll-snap-points
का इस्तेमाल, स्वाइप करने और कीबोर्ड से इंटरैक्ट करने के लिए किया जाता है. इससे स्क्रोल करने के लिए सही जगहें मिलती हैं- डीप लिंक के लिए यूआरएल हैश. इससे ब्राउज़र में, पेज पर स्क्रोल करने की सुविधा और शेयर करने की सुविधा मिलती है
<a>
औरid="#hash"
एलिमेंट मार्कअप के साथ स्क्रीन रीडर की सुविधाprefers-reduced-motion
का इस्तेमाल, क्रॉसफ़ेड ट्रांज़िशन और पेज पर तुरंत स्क्रोल करने की सुविधा चालू करने के लिए किया जाता है- चुने गए टैब को डाइनैमिक तरीके से अंडरलाइन करने और उसका रंग बदलने के लिए, ड्राफ़्ट में मौजूद
@scroll-timeline
वेब सुविधा
एचटीएमएल
यहां यूज़र एक्सपीरियंस (यूएक्स) इस तरह काम करता है: किसी लिंक पर क्लिक करने पर, यूआरएल में नेस्ट किए गए पेज की स्थिति दिखती है. इसके बाद, ब्राउज़र के स्क्रोल करने पर, कॉन्टेंट एरिया अपडेट हो जाता है.
इसमें कुछ स्ट्रक्चरल कॉन्टेंट मेंबर हैं: लिंक और :target
. हमें लिंक की एक सूची चाहिए, जिसके लिए <nav>
सबसे सही है. साथ ही, हमें <article>
एलिमेंट की एक सूची चाहिए, जिसके लिए <section>
सबसे सही है. हर लिंक हैश, किसी सेक्शन से मैच करेगा. इससे ब्राउज़र, ऐंकरिंग की मदद से स्क्रोल कर पाएगा.
उदाहरण के लिए, किसी लिंक पर क्लिक करने से Chrome 89 में :target
लेख पर अपने-आप फ़ोकस हो जाता है. इसके लिए, JS की ज़रूरत नहीं होती. इसके बाद, उपयोगकर्ता हमेशा की तरह अपने इनपुट डिवाइस से लेख के कॉन्टेंट को स्क्रोल कर सकता है. यह बिना किसी शुल्क के उपलब्ध कॉन्टेंट है. इसकी जानकारी मार्कअप में दी गई है.
मैंने टैब को व्यवस्थित करने के लिए, इस मार्कअप का इस्तेमाल किया है:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
मैं <a>
और <article>
एलिमेंट के बीच कनेक्शन बनाने के लिए, href
और id
प्रॉपर्टी का इस्तेमाल इस तरह कर सकता हूं:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
इसके बाद, मैंने लेखों में अलग-अलग मात्रा में लॉरेम टेक्स्ट डाला. साथ ही, लिंक में अलग-अलग लंबाई और इमेज सेट वाले टाइटल डाले. कॉन्टेंट मिलने के बाद, हम लेआउट बनाना शुरू कर सकते हैं.
स्क्रोल किए जा सकने वाले लेआउट
इस कॉम्पोनेंट में तीन तरह की स्क्रोल करने की जगहें होती हैं:
- नेविगेशन (गुलाबी) को हॉरिज़ॉन्टल तरीके से स्क्रोल किया जा सकता है
- कॉन्टेंट एरिया (नीला) को हॉरिज़ॉन्टल तौर पर स्क्रोल किया जा सकता है
- हर लेख आइटम (हरा) को वर्टिकल तौर पर स्क्रोल किया जा सकता है.

स्क्रोलिंग में दो तरह के एलिमेंट शामिल होते हैं:
- खिड़की
तय किए गए डाइमेंशन वाला एक बॉक्स, जिसमेंoverflow
प्रॉपर्टी स्टाइल है. - बड़ा कॉन्टेंट एरिया
इस लेआउट में, लिस्ट कंटेनर बड़े होते हैं. जैसे, nav links, section articles, और article contents.
<snap-tabs>
लेआउट
मैंने सबसे ऊपर वाला लेआउट, फ़्लेक्स (फ़्लेक्सबॉक्स) चुना था. मैंने दिशा को column
पर सेट किया है, इसलिए हेडर और सेक्शन को वर्टिकल क्रम में रखा गया है. यह हमारी पहली स्क्रोल विंडो है. इसमें ओवरफ़्लो हिडन के साथ सब कुछ छिपा होता है. हेडर और सेक्शन में जल्द ही ओवरस्क्रोल की सुविधा उपलब्ध होगी.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
रंग-बिरंगे तीन स्क्रोल वाले डायग्राम पर वापस जाएं:
<header>
अब (गुलाबी रंग) स्क्रोल कंटेनर के तौर पर इस्तेमाल किया जा सकता है.<section>
, (नीले रंग का) स्क्रोल कंटेनर बनने के लिए तैयार है.
नीचे VisBug से हाइलाइट किए गए फ़्रेम से, हमें यह पता चलता है कि स्क्रोल कंटेनर ने कौनसी विंडो बनाई हैं.

टैब <header>
लेआउट
अगला लेआउट भी लगभग ऐसा ही है: मैंने वर्टिकल ऑर्डरिंग बनाने के लिए फ़्लेक्स का इस्तेमाल किया है.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
को लिंक के ग्रुप के साथ हॉरिज़ॉन्टल तरीके से घूमना चाहिए. साथ ही, यह हेडर लेआउट उस स्टेज को सेट करने में मदद करता है. यहां कोई भी एलिमेंट पूरी तरह से पोज़िशन नहीं किया गया है!

इसके बाद, स्क्रोल करने की स्टाइल. हमें पता चला कि हम स्क्रोल करने की स्टाइल को हेडर और सेक्शन, दोनों के लिए शेयर कर सकते हैं. इसलिए, हमने एक यूटिलिटी क्लास .scroll-snap-x
बनाई है.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
इन सभी को x ऐक्सिस पर ओवरफ़्लो की ज़रूरत होती है. साथ ही, ओवरस्क्रोल को रोकने के लिए स्क्रोल कंटेनमेंट, टच डिवाइसों के लिए छिपे हुए स्क्रोलबार, और कॉन्टेंट प्रज़ेंटेशन एरिया को लॉक करने के लिए स्क्रोल-स्नैप की ज़रूरत होती है. हमारे कीबोर्ड टैब का क्रम ऐक्सेस किया जा सकता है. साथ ही, किसी भी इंटरैक्शन गाइड पर फ़ोकस किया जा सकता है. स्क्रोल स्नैप कंटेनर को कीबोर्ड से भी कैरसेल स्टाइल में इंटरैक्ट करने की सुविधा मिलती है.
टैब हेडर <nav>
का लेआउट
नेविगेशन लिंक को एक लाइन में, बिना किसी लाइन ब्रेक के, वर्टिकल तौर पर बीच में अलाइन किया जाना चाहिए. साथ ही, हर लिंक आइटम को स्क्रोल-स्नैप कंटेनर पर स्नैप करना चाहिए. 2021 के सीएसएस के लिए, तेज़ी से काम करने की सुविधा!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
हर लिंक की स्टाइल और साइज़ खुद तय होता है. इसलिए, नेविगेशन लेआउट में सिर्फ़ दिशा और फ़्लो तय करना होता है. नेविगेशन आइटम की चौड़ाई अलग-अलग होने से, टैब के बीच ट्रांज़िशन मज़ेदार लगता है. ऐसा इसलिए होता है, क्योंकि इंडिकेटर अपनी चौड़ाई को नए टारगेट के हिसाब से अडजस्ट करता है. इसमें मौजूद एलिमेंट की संख्या के आधार पर, ब्राउज़र स्क्रोलबार को रेंडर करेगा या नहीं.

टैब <section>
लेआउट
यह सेक्शन एक फ़्लेक्स आइटम है और इसे ज़्यादा जगह की ज़रूरत होती है. इसे लेखों को रखने के लिए कॉलम भी बनाने होते हैं. सीएसएस 2021 के लिए, एक बार फिर तेज़ी से काम किया गया! block-size: 100%
इस एलिमेंट को पैरंट के हिसाब से ज़्यादा से ज़्यादा जगह में फैलाता है. इसके बाद, अपने लेआउट के लिए, यह पैरंट की चौड़ाई के बराबर 100%
कॉलम की एक सीरीज़ बनाता है. यहां प्रतिशत का इस्तेमाल करना बेहतर है, क्योंकि हमने पैरंट पर कुछ पाबंदियां लगाई हैं.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
ऐसा लगता है कि हम "ज़्यादा से ज़्यादा वर्टिकल स्पेस का इस्तेमाल करो" कह रहे हैं. हालांकि, हमने हेडर को flex-shrink: 0
पर सेट किया है. यह इस तरह के वर्टिकल स्पेस के इस्तेमाल को रोकता है. इससे, पूरी ऊंचाई वाले कॉलम के सेट के लिए लाइन की ऊंचाई सेट हो जाती है. auto-flow
स्टाइल, ग्रिड को हमेशा चाइल्ड को हॉरिज़ॉन्टल लाइन में रखने के लिए कहती है. इसमें रैपिंग नहीं होती है. यह ठीक वैसा ही है जैसा हमें चाहिए. इससे पैरंट विंडो ओवरफ़्लो हो जाती है.

कभी-कभी मुझे इन्हें समझने में मुश्किल होती है! इस सेक्शन का एलिमेंट, एक बॉक्स में फ़िट हो रहा है. हालांकि, इसने बॉक्स का एक सेट भी बनाया है. हमें उम्मीद है कि विज़ुअल और जानकारी से आपको मदद मिल रही होगी.
टैब <article>
लेआउट
उपयोगकर्ता को लेख के कॉन्टेंट को स्क्रोल करने की सुविधा मिलनी चाहिए. साथ ही, स्क्रोलबार सिर्फ़ तब दिखने चाहिए, जब कॉन्टेंट तय जगह से ज़्यादा हो. लेख के ये एलिमेंट सही जगह पर हैं. ये एक साथ स्क्रोल पेरेंट और स्क्रोल चाइल्ड होते हैं. यहां ब्राउज़र, टच, माउस, और कीबोर्ड से होने वाले कुछ मुश्किल इंटरैक्शन को मैनेज कर रहा है.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
मैंने लेखों को उनके पैरंट स्क्रोलर में स्नैप करने का विकल्प चुना है. मुझे यह बहुत पसंद आया कि नेविगेशन लिंक आइटम और लेख के एलिमेंट, अपने-अपने स्क्रोल कंटेनर के इनलाइन-स्टार्ट में कैसे स्नैप होते हैं. यह एक अच्छी और भरोसेमंद रिलेशनशिप की तरह दिखता है.

यह लेख, ग्रिड चाइल्ड है. इसका साइज़ पहले से तय किया गया है. यह व्यूपोर्ट का वह हिस्सा है जहां हमें स्क्रोल करने का यूज़र एक्सपीरियंस देना है. इसका मतलब है कि मुझे यहां ऊंचाई या चौड़ाई की किसी भी स्टाइल की ज़रूरत नहीं है. मुझे सिर्फ़ यह तय करना है कि यह कैसे ओवरफ़्लो होता है. मैंने overflow-y को auto पर सेट किया है. इसके बाद, स्क्रोल इंटरैक्शन को overscroll-behavior प्रॉपर्टी के साथ ट्रैप किया है.
तीन स्क्रोल एरिया का रीकैप
नीचे, मैंने सिस्टम सेटिंग में "स्क्रोलबार हमेशा दिखाएं" विकल्प चुना है. मुझे लगता है कि इस सेटिंग के चालू होने पर लेआउट का काम करना बहुत ज़रूरी है. साथ ही, मेरे लिए लेआउट और स्क्रोल ऑर्केस्ट्रेशन की समीक्षा करना भी ज़रूरी है.

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

स्क्रोल लेआउट पूरी तरह से काम कर रहे हैं: स्नैपिंग, डीप लिंक करने की सुविधा, और कीबोर्ड से ऐक्सेस करने की सुविधा. UX को बेहतर बनाने, स्टाइल, और लोगों की दिलचस्पी बढ़ाने के लिए मज़बूत बुनियाद.
सुविधा की हाइलाइट
स्नैप किए गए बच्चों को स्क्रोल करने पर, उनका साइज़ बदलने के दौरान उनकी जगह लॉक रहती है. इसका मतलब है कि डिवाइस को घुमाने या ब्राउज़र का साइज़ बदलने पर, JavaScript को कुछ भी दिखाने की ज़रूरत नहीं होगी. इसे Chromium DevTools Device Mode में आज़माएं. इसके लिए, Responsive के अलावा कोई दूसरा मोड चुनें. इसके बाद, डिवाइस फ़्रेम का साइज़ बदलें. ध्यान दें कि एलिमेंट, कॉन्टेंट के साथ लॉक रहता है और दिखता रहता है. यह सुविधा तब से उपलब्ध है, जब Chromium ने स्पेसिफ़िकेशन से मेल खाने के लिए, अपने सिस्टम को अपडेट किया था. इसके बारे में यह ब्लॉग पोस्ट पढ़ें.
ऐनिमेशन
यहां ऐनिमेशन का मकसद, इंटरैक्शन को यूज़र इंटरफ़ेस (यूआई) फ़ीडबैक से साफ़ तौर पर जोड़ना है. इससे उपयोगकर्ता को सभी कॉन्टेंट आसानी से खोजने में मदद मिलती है. मैं वीडियो में ज़रूरत के हिसाब से और खास मकसद के साथ मोशन जोड़ूंगी. उपयोगकर्ता अब अपने ऑपरेटिंग सिस्टम में, मोशन से जुड़ी अपनी प्राथमिकताएं सेट कर सकते हैं. मुझे अपने इंटरफ़ेस में, उनकी प्राथमिकताओं के हिसाब से जवाब देने में बहुत अच्छा लगता है.
मैं टैब के नीचे मौजूद लाइन को लेख की स्क्रोल पोज़िशन से लिंक करूँगा/करूँगी. स्नैपिंग सिर्फ़ अलाइनमेंट को बेहतर नहीं बनाती, बल्कि यह ऐनिमेशन की शुरुआत और आखिर को भी बेहतर बनाती है.
इससे <nav>
, कॉन्टेंट से जुड़ा रहता है. यह मिनी-मैप की तरह काम करता है.
हम सीएसएस और JS, दोनों से उपयोगकर्ता की मोशन सेटिंग की जांच करेंगे. यहां कुछ बेहतरीन जगहों के बारे में बताया गया है!
स्क्रोल करने का तरीका
:target
और element.scrollIntoView()
, दोनों के मोशन को बेहतर बनाया जा सकता है. डिफ़ॉल्ट रूप से, यह तुरंत होता है. ब्राउज़र सिर्फ़ स्क्रोल करने की
जगह सेट करता है. अगर हमें उस स्क्रोल पोज़िशन पर ट्रांज़िशन करना हो, तो क्या होगा?
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
हम यहां मोशन का इस्तेमाल कर रहे हैं. साथ ही, ऐसा मोशन इस्तेमाल कर रहे हैं जिसे उपयोगकर्ता कंट्रोल नहीं करता (जैसे कि स्क्रोल करना). इसलिए, हम इस स्टाइल का इस्तेमाल सिर्फ़ तब करते हैं, जब उपयोगकर्ता ने अपने ऑपरेटिंग सिस्टम में मोशन कम करने की सुविधा को चालू न किया हो. इस तरह, हम स्क्रोल करने की सुविधा सिर्फ़ उन लोगों के लिए उपलब्ध कराते हैं जिन्हें इससे कोई समस्या नहीं है.
टैब इंडिकेटर
इस ऐनिमेशन का मकसद, इंडिकेटर को कॉन्टेंट की स्थिति से जोड़ना है. मैंने उन लोगों के लिए border-bottom
स्टाइल में कलर क्रॉसफ़ेड का इस्तेमाल किया है जिन्हें मोशन कम पसंद है. साथ ही, मैंने उन लोगों के लिए स्क्रोल से लिंक किए गए स्लाइडिंग + कलर फ़ेड ऐनिमेशन का इस्तेमाल किया है जिन्हें मोशन से कोई समस्या नहीं है.
Chromium Devtools में, मैं अपनी पसंद के मुताबिक टॉगल कर सकता हूं और ट्रांज़िशन की दो अलग-अलग स्टाइल दिखा सकता हूं. इसे बनाने में मुझे बहुत मज़ा आया.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
जब उपयोगकर्ता को मोशन कम पसंद होता है, तब मैं .snap-indicator
को छिपा देता हूं, क्योंकि अब मुझे इसकी ज़रूरत नहीं है. इसके बाद, मैं इसे border-block-end
स्टाइल और transition
से बदल देता हूं. टैब के साथ इंटरैक्ट करते समय यह भी ध्यान दें कि चालू नेविगेशन आइटम में न सिर्फ़ ब्रैंड के रंग वाली अंडरलाइन हाइलाइट होती है, बल्कि उसके टेक्स्ट का रंग भी ज़्यादा गहरा होता है. ऐक्टिव एलिमेंट में टेक्स्ट के रंग का कंट्रास्ट ज़्यादा होता है. साथ ही, इसमें नीचे की ओर हल्के रंग का ऐक्सेंट होता है.
सीएसएस की कुछ और लाइनें जोड़ने से, लोगों को लगेगा कि उनकी ज़रूरतों का ध्यान रखा जा रहा है. इसका मतलब है कि हम उनकी मोशन से जुड़ी प्राथमिकताओं का ध्यान रख रहे हैं. हालाँकि, मुझे यह पसंद है।
@scroll-timeline
ऊपर दिए गए सेक्शन में, मैंने आपको बताया कि मोशन कम करने वाले क्रॉसफ़ेड स्टाइल को कैसे मैनेज किया जाता है. इस सेक्शन में, मैं आपको बताऊंगा कि मैंने इंडिकेटर और स्क्रोल एरिया को एक साथ कैसे लिंक किया. अब कुछ मज़ेदार एक्सपेरिमेंटल चीज़ें आने वाली हैं. हमें उम्मीद है कि आपको भी उतनी ही खुशी हुई होगी जितनी कि हमें हुई है.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
सबसे पहले, मैं JavaScript से उपयोगकर्ता की मोशन सेटिंग की जांच करता हूं. अगर इसका नतीजा false
है, तो इसका मतलब है कि उपयोगकर्ता को मोशन कम पसंद है. ऐसे में, हम स्क्रोल लिंक करने वाले मोशन इफ़ेक्ट में से किसी को भी नहीं चलाएंगे.
if (motionOK) {
// motion based animation code
}
यह जवाब लिखते समय, @scroll-timeline
के लिए ब्राउज़र सपोर्ट उपलब्ध नहीं है. यह सिर्फ़ एक ड्राफ़्ट स्पेसिफ़िकेशन है. इसमें सिर्फ़ एक्सपेरिमेंट के तौर पर लागू की गई सुविधाएं शामिल हैं. हालांकि, इसमें एक पॉलीफ़िल है, जिसका इस्तेमाल मैंने इस डेमो में किया है.
ScrollTimeline
सीएसएस और JavaScript, दोनों से स्क्रोल टाइमलाइन बनाई जा सकती हैं. हालांकि, मैंने JavaScript का इस्तेमाल किया, ताकि मैं ऐनिमेशन में लाइव एलिमेंट मेज़रमेंट का इस्तेमाल कर सकूं.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
मुझे एक चीज़ को दूसरी चीज़ की स्क्रोल पोज़िशन के हिसाब से स्क्रोल करना है. इसके लिए, ScrollTimeline
बनाकर, स्क्रोल लिंक के ड्राइवर, scrollSource
को तय किया जाता है.
आम तौर पर, वेब पर कोई ऐनिमेशन, ग्लोबल टाइम फ़्रेम के हिसाब से चलता है. हालांकि, मेमोरी में मौजूद कस्टम sectionScrollTimeline
की मदद से, मैं इसे बदल सकता हूं.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
ऐनिमेशन के मुख्य फ़्रेम के बारे में बताने से पहले, मुझे लगता है कि यह बताना ज़रूरी है कि स्क्रोल करने की सुविधा को फ़ॉलो करने वाले tabindicator
को कस्टम टाइमलाइन के आधार पर ऐनिमेट किया जाएगा. यह टाइमलाइन, हमारे सेक्शन के स्क्रोल पर आधारित होगी. इससे लिंक करने की प्रोसेस पूरी हो जाती है. हालांकि, इसमें आखिरी चीज़ नहीं है. यानी, ऐनिमेशन के लिए स्टेटफ़ुल पॉइंट नहीं हैं. इन्हें कीफ़्रेम भी कहा जाता है.
डाइनैमिक कीफ़्रेम
@scroll-timeline
के साथ ऐनिमेशन बनाने के लिए, सीएसएस का इस्तेमाल किया जा सकता है. हालांकि, मैंने जो ऐनिमेशन चुना है वह बहुत डाइनैमिक है. auto
चौड़ाई के बीच ट्रांज़िशन करने का कोई तरीका नहीं है. साथ ही, बच्चों की लंबाई के आधार पर कई मुख्य फ़्रेम डाइनैमिक तरीके से बनाने का कोई तरीका नहीं है.
हालांकि, JavaScript को यह जानकारी पाने का तरीका पता है. इसलिए, हम खुद ही बच्चों पर दोहराएंगे और रनटाइम पर कैलकुलेट की गई वैल्यू को हासिल करेंगे:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
हर tabnavitem
के लिए, offsetLeft
पोज़िशन को डीस्ट्रक्चर करें और एक स्ट्रिंग दिखाएं. यह स्ट्रिंग, offsetLeft
पोज़िशन को translateX
वैल्यू के तौर पर इस्तेमाल करती है. इससे ऐनिमेशन के लिए, ट्रांसफ़ॉर्म करने वाले चार कीफ़्रेम बन जाते हैं. चौड़ाई के लिए भी यही तरीका अपनाया जाता है. हर चौड़ाई से पूछा जाता है कि उसकी डाइनैमिक चौड़ाई क्या है. इसके बाद, इसे कीफ़्रेम वैल्यू के तौर पर इस्तेमाल किया जाता है.
यहां मेरे फ़ॉन्ट और ब्राउज़र की प्राथमिकताओं के आधार पर, आउटपुट का उदाहरण दिया गया है:
TranslateX कीफ़्रेम:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
चौड़ाई के मुख्य फ़्रेम:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
रणनीति के बारे में खास जानकारी देने के लिए, टैब इंडिकेटर अब चार मुख्य फ़्रेम में ऐनिमेशन करेगा. यह सेक्शन स्क्रोलर की स्क्रोल स्नैप पोज़िशन पर निर्भर करेगा. स्नैप पॉइंट, हमारे कीफ़्रेम के बीच साफ़ तौर पर अंतर करते हैं. साथ ही, ये ऐनिमेशन को सिंक्रनाइज़ करने में मदद करते हैं.

उपयोगकर्ता के इंटरैक्शन के हिसाब से ऐनिमेशन चलता है. इसमें इंडिकेटर की चौड़ाई और पोज़िशन, एक सेक्शन से दूसरे सेक्शन में बदलते हुए दिखती है. साथ ही, यह स्क्रोल के साथ पूरी तरह से ट्रैक करता है.
आपने शायद ध्यान न दिया हो, लेकिन मुझे हाइलाइट किए गए नेविगेशन आइटम के चुने जाने पर, रंग बदलने की सुविधा पर बहुत गर्व है.
हाइलाइट किए गए आइटम का कंट्रास्ट ज़्यादा होने पर, चुना नहीं गया हल्का ग्रे रंग और भी हल्का दिखता है. टेक्स्ट के रंग को ट्रांज़िशन करना आम बात है. जैसे, कर्सर घुमाने पर और चुने जाने पर, लेकिन स्क्रोल करने पर रंग को ट्रांज़िशन करना एक अलग लेवल की बात है. यह अंडरलाइन इंडिकेटर के साथ सिंक होता है.
मैंने यह काम इस तरह किया:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
हर टैब नेविगेशन लिंक में, रंग बदलने का नया ऐनिमेशन होना चाहिए. साथ ही, यह अंडरलाइन इंडिकेटर की तरह ही स्क्रोल टाइमलाइन को ट्रैक करता हो. मैंने पहले वाली टाइमलाइन का इस्तेमाल किया है: इसका काम स्क्रोल करने पर टिक मार्क दिखाना है. इसलिए, हम इस टिक मार्क का इस्तेमाल किसी भी तरह के ऐनिमेशन में कर सकते हैं. मैंने पहले की तरह, लूप में चार कीफ़्रेम बनाए हैं और रंग वापस कर दिए हैं.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
var(--text-active-color)
रंग वाले कीफ़्रेम में लिंक को हाइलाइट किया गया है. इसके अलावा, यह टेक्स्ट का सामान्य रंग है. इसमें नेस्टेड लूप का इस्तेमाल किया गया है, जिससे यह काफ़ी आसान हो जाता है. ऐसा इसलिए, क्योंकि आउटर लूप हर नेविगेशन आइटम होता है और इनर लूप हर नेविगेशन आइटम के निजी कीफ़्रेम होते हैं. मैं यह देखता हूं कि आउटर लूप एलिमेंट, इनर लूप एलिमेंट के जैसा है या नहीं. साथ ही, इसका इस्तेमाल यह जानने के लिए करता हूं कि इसे कब चुना गया है.
मुझे इसे लिखने में बहुत मज़ा आया. बहुत ज़्यादा.
JavaScript में और भी सुधार
हम आपको याद दिलाना चाहते हैं कि यहां दिखाई गई मुख्य सुविधा, JavaScript के बिना काम करती है. अब देखते हैं कि JavaScript उपलब्ध होने पर, इसे कैसे बेहतर बनाया जा सकता है.
डीप लिंक
डीप लिंक, मोबाइल से जुड़ा शब्द है. हालांकि, मुझे लगता है कि यहां टैब के साथ डीप लिंक का मकसद पूरा हो रहा है. ऐसा इसलिए, क्योंकि किसी टैब के कॉन्टेंट का यूआरएल सीधे तौर पर शेयर किया जा सकता है. ब्राउज़र, पेज पर उस आईडी पर जाएगा जो यूआरएल हैश में मैच किया गया है. मुझे पता चला कि इस onload
हैंडलर से, सभी प्लैटफ़ॉर्म पर असर पड़ा.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
स्क्रोल करने की प्रोसेस खत्म होने पर सिंक्रनाइज़ेशन
हमारे उपयोगकर्ता हमेशा क्लिक नहीं करते या कीबोर्ड का इस्तेमाल नहीं करते. कभी-कभी वे सिर्फ़ स्क्रोल करते हैं, जैसा कि उन्हें करना चाहिए. जब सेक्शन स्क्रोलर स्क्रोल करना बंद कर देता है, तो वह जिस भी सेक्शन पर रुकता है उसे टॉप नेविगेशन बार में हाइलाइट किया जाना चाहिए.
स्क्रोल खत्म होने का इंतज़ार करने का तरीका यहां दिया गया है:
js
tabsection.addEventListener('scroll', () => {
clearTimeout(tabsection.scrollEndTimer);
tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100);
});
जब भी सेक्शन स्क्रोल किए जा रहे हों, तो सेक्शन के टाइम आउट को मिटा दें. इसके बाद, नया सेक्शन शुरू करें. जब सेक्शन स्क्रोल होना बंद हो जाएं, तो टाइमआउट को न हटाएं. साथ ही, स्क्रोलिंग रुकने के 100 मि॰से॰ बाद, इवेंट ट्रिगर करें. जब यह इवेंट ट्रिगर होता है, तो उस फ़ंक्शन को कॉल करें जो यह पता लगाने की कोशिश करता है कि उपयोगकर्ता ने वीडियो कहां रोका था.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
मान लें कि स्क्रोल स्नैप हो गया है. ऐसे में, स्क्रोल एरिया की चौड़ाई से मौजूदा स्क्रोल पोज़िशन को भाग देने पर, पूर्णांक मिलना चाहिए, न कि दशमलव. इसके बाद, मैं इस कैलकुलेट किए गए इंडेक्स के ज़रिए, हमारी कैश मेमोरी से कोई navitem पाने की कोशिश करता हूं. अगर उसे कोई navitem मिलता है, तो मैं उसे मैच के तौर पर भेजता हूं, ताकि उसे चालू किया जा सके.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
ऐक्टिव टैब सेट करने की प्रोसेस में, सबसे पहले मौजूदा ऐक्टिव टैब को हटाया जाता है. इसके बाद, आने वाले नेविगेशन आइटम को ऐक्टिव स्टेट एट्रिब्यूट दिया जाता है. scrollIntoView()
को कॉल करने पर, सीएसएस के साथ एक मज़ेदार इंटरैक्शन होता है. इस पर ध्यान देना ज़रूरी है.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
हॉरिज़ॉन्टल स्क्रोल स्नैप यूटिलिटी सीएसएस में, हमने एक मीडिया क्वेरी को नेस्ट किया है. यह क्वेरी, उपयोगकर्ता के मोशन टॉलरेंट होने पर smooth
स्क्रोलिंग लागू करती है. JavaScript, स्क्रोल एलिमेंट को व्यू में लाने के लिए कॉल कर सकती है. साथ ही, सीएसएस, यूज़र एक्सपीरियंस (यूएक्स) को मैनेज कर सकती है.
कभी-कभी ये दोनों मिलकर बहुत अच्छा काम करते हैं.
नतीजा
अब आपको पता चल गया है कि मैंने यह कैसे किया. अब आप इसे कैसे करेंगे?! इससे कॉम्पोनेंट आर्किटेक्चर को मज़ेदार बनाया जा सकता है! कौन अपने पसंदीदा फ़्रेमवर्क में स्लॉट के साथ पहला वर्शन बनाएगा? 🙂
आइए, हम अपने तरीकों में विविधता लाएं और वेब पर काॅन्टेंट पोस्ट करने के सभी तरीके जानें. Glitch बनाएँ, मुझे ट्वीट करें और अपना वर्शन भेजें. इसके बाद, मैं उसे यहाँ नीचे मौजूद कम्यूनिटी रीमिक्स सेक्शन में जोड़ दूँगा.
कम्यूनिटी रीमिक्स
- @devnook, @rob_dodson, और @DasSurma के साथ वेब कॉम्पोनेंट: article.
- @jhvanderschee के साथ बटन: Codepen.