टैब कॉम्पोनेंट बनाना

iOS और Android ऐप्लिकेशन से मिलते-जुलते टैब कॉम्पोनेंट बनाने के बारे में खास जानकारी.

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

डेमो

अगर आप वीडियो पसंद करते हैं, तो यहां इस पोस्ट का YouTube वर्शन दिया गया है:

खास जानकारी

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

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

कोलाज का कॉम्बिनेशन बहुत ही अस्त-व्यस्त है. इसकी वजह यह है कि कॉम्पोनेंट के कॉन्सेप्ट पर वेब पर, अलग-अलग तरह की स्टाइल लागू होती हैं
पिछले 10 साल के टैब कॉम्पोनेंट वेब डिज़ाइन स्टाइल का कोलाज

वेब रणनीति

कुल मिलाकर, मुझे यह कॉम्पोनेंट बनाना काफ़ी आसान लगा, वेब प्लैटफ़ॉर्म की कुछ अहम सुविधाओं की बदौलत:

  • सही स्क्रोल स्टॉप पोज़िशन के साथ, शानदार स्वाइप और कीबोर्ड इंटरैक्शन के लिए scroll-snap-points
  • ब्राउज़र से हैंडल किए जाने वाले इन-पेज स्क्रोल ऐंकर और शेयर करने की सुविधा के लिए, यूआरएल हैश के ज़रिए डीप लिंक
  • <a> और id="#hash" एलिमेंट मार्कअप के साथ स्क्रीन रीडर की सुविधा
  • क्रॉसफ़ेड ट्रांज़िशन और इंस्टैंट इन-पेज स्क्रोलिंग को चालू करने के लिए prefers-reduced-motion
  • चुने गए टैब को डाइनैमिक रूप से अंडरलाइन करने और रंग बदलने के लिए, इन-ड्राफ़्ट @scroll-timeline वेब की सुविधा

एचटीएमएल

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

इस कॉन्टेंट में कुछ ऐसे सदस्य भी हैं जो स्ट्रक्चर इस्तेमाल करते हैं: लिंक और :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>

मेरे पास इस तरह की href और id प्रॉपर्टी की मदद से, <a> और <article> एलिमेंट के बीच कनेक्शन बनाने का विकल्प है:

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

इसके बाद मैंने लेखों में थोड़ी-बहुत मात्रा और टाइटल की मिक्स लंबाई और इमेज सेट वाले लिंक डाले. हम लेआउट की शुरुआत कर सकते हैं.

स्क्रोलिंग लेआउट

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

  • नेविगेशन (गुलाबी) ऊपर-नीचे स्क्रोल किया जा सकता है
  • कॉन्टेंट एरिया (नीला) हॉरिज़ॉन्टल तौर पर स्क्रोल किया जा सकता है
  • लेख के हर आइटम (हरा) को वर्टिकल तौर पर स्क्रोल किया जा सकता है.
3 रंग-बिरंगे बॉक्स, जिनमें मिलते-जुलते रंग वाले दिशा-निर्देश हैं. ये बॉक्स, स्क्रोल करने की जगहों को आउटलाइन करते हैं और स्क्रोल करने की दिशा दिखाते हैं.

स्क्रोल करने में दो तरह के एलिमेंट शामिल होते हैं:

  1. विंडो
    तय किए गए डाइमेंशन वाला बॉक्स, जिसमें overflow प्रॉपर्टी स्टाइल शामिल है.
  2. बड़े साइज़ का सरफ़ेस
    इस लेआउट में, इन कंटेनर की सूची होती है: नेविगेशन लिंक, सेक्शन लेख, और लेख का कॉन्टेंट.

<snap-tabs> लेआउट

मैंने टॉप लेवल का जो लेआउट चुना वह फ़्लेक्सिबल (Flexbox) था. मैंने दिशा को 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 against 
needing 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }

रंग-बिरंगे 3-स्क्रोल डायग्राम की ओर वापस जाना:

  • <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 को लिंक के ग्रुप के साथ हॉरिज़ॉन्टल यात्रा करना चाहिए. साथ ही, हेडर लेआउट से यह चरण सेट करने में मदद मिलती है. यहां कोई ऐब्सलूट एलिमेंट मौजूद नहीं है!

नेविगेशन और span.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;
}

मैंने लेखों को उनके पैरंट स्क्रोलर में स्नैप करना चुना. मुझे नेविगेशन लिंक के आइटम और लेख के एलिमेंट अपने-अपने स्क्रोल कंटेनर के इनलाइन-स्टार्ट में स्नैप करते हैं. यह एक हार्दिक संबंध की तरह दिखता और महसूस होता है.

लेख और इसके चाइल्ड एलिमेंट पर हॉटपिंक ओवरले हैं. इनसे यह पता चलता है कि कॉम्पोनेंट में स्पेस, किस दिशा में लेते हैं और किस दिशा में ओवरफ़्लो होती है

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

3 स्क्रोलिंग एरिया रीकैप

नीचे मैंने अपनी सिस्टम सेटिंग में "हमेशा स्क्रोलबार दिखाएं" को चुना है. मुझे लगता है कि इस सेटिंग के चालू होने से लेआउट का काम करना दोगुना ज़रूरी है, क्योंकि इससे मुझे लेआउट और स्क्रोल ऑर्केस्ट्रा का आकलन करने में मदद मिलती है.

तीन स्क्रोलबार दिखने के लिए सेट हैं, जो अब लेआउट स्पेस का इस्तेमाल कर रहे हैं और हमारा कॉम्पोनेंट अब भी बेहतरीन दिख रहा है

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

DevTools की मदद से, इसे विज़ुअलाइज़ किया जा सकता है:

स्क्रोल करने वाली जगहों में ग्रिड और फ़्लेक्सबॉक्स टूल ओवरले होते हैं. इनसे कॉम्पोनेंट में ली जाने वाली जगह और दिशा में ओवरफ़्लो होती है
Chromium Devtools, ऐंकर एलिमेंट से भरा हुआ फ़्लेक्सबॉक्स नेविगेशन एलिमेंट लेआउट, लेख के एलिमेंट से भरा ग्रिड सेक्शन लेआउट, और लेख के सभी पैराग्राफ़ और हेडिंग एलिमेंट दिखा रहा है.

स्क्रोल लेआउट पूरे हो गए हैं: स्नैप करना, डीप लिंक करना, और कीबोर्ड का इस्तेमाल करना. UX को बेहतर बनाने, स्टाइल और आनंद के लिए मज़बूत बुनियाद.

सुविधा की हाइलाइट

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

Animation

ऐनिमेशन वाले इस फ़ॉर्मैट का मकसद, यूज़र इंटरफ़ेस (यूआई) सुझाव के साथ इंटरैक्शन को साफ़ तौर पर लिंक करना है. इससे उपयोगकर्ताओं को पूरा कॉन्टेंट आसानी से खोजने में मदद मिलती है या उन्हें गाइड करने में मदद मिलती है. मैं किसी मकसद से और शर्त के साथ मोशन जोड़ूंगी. अब उपयोगकर्ता अपने ऑपरेटिंग सिस्टम में अपनी मोशन सेटिंग के बारे में बता सकते हैं. मुझे अपने इंटरफ़ेस में उनकी प्राथमिकताओं का जवाब देने में बहुत आनंद आता है.

हम लेख को स्क्रोल करने की पोज़िशन के साथ, टैब की अंडरलाइन को लिंक करेंगे. स्नैप करना सिर्फ़ ऐनिमेशन की शुरुआत और अंत को बेहतर ढंग से शामिल नहीं करता. इससे <nav>, कॉन्टेंट से मिनी-मैप की तरह काम करता है. हम CSS और 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 पोज़िशन को नष्ट करें और वह स्ट्रिंग दें जो इसे 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"]

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

ऐक्टिव टैब और इनऐक्टिव टैब, VisBug ओवरले के साथ दिखाए जाते हैं, जो दोनों के लिए पासिंग कंट्रास्ट स्कोर दिखाते हैं

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

आपने शायद ध्यान न दिया हो, लेकिन मुझे कलर ट्रांज़िशन पर बहुत गर्व है, क्योंकि हाइलाइट किए गए नेविगेशन आइटम को चुन लिया गया है.

हाइलाइट किए गए आइटम में ज़्यादा कंट्रास्ट होने पर, चुना गया हल्का स्लेटी रंग ज़्यादा पीछे दिखता है. माउस घुमाने पर और चुने जाने पर टेक्स्ट के लिए रंग का ट्रांज़िशन करना आम बात है. हालांकि, स्क्रोल करने पर उस रंग का ट्रांज़िशन, अंडरलाइन दिखाने के दिशा-निर्देश के साथ सिंक में होता है.

मैंने इसे इस तरह किया:

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 के बिना भी काम करती है. इसके बाद, आइए देखते हैं कि JS उपलब्ध होने पर हम इसे कैसे बेहतर कर सकते हैं.

डीप लिंक आम तौर पर मोबाइल के लिए इस्तेमाल किए जाते हैं, लेकिन मुझे लगता है कि डीप लिंक का मकसद यहां टैब के साथ पूरा होना चाहिए, ताकि सीधे टैब के कॉन्टेंट का यूआरएल शेयर किया जा सके. ब्राउज़र, इन-पेज उस आईडी पर नेविगेट करेगा जो यूआरएल हैश से मेल खाती है. मैंने पाया कि इस 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);
};

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

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 से एलिमेंट को स्क्रोल करके देखने के लिए आसानी से कॉल किए जा सकते हैं. साथ ही, सीएसएस, UX को जानकारी के साथ मैनेज कर सकती है. ये कभी-कभी तो शानदार और मज़ेदार गेम बनाते हैं.

नतीजा

अब आपको पता चल गया है कि मैंने इसे कैसे किया, तो आपको कैसा लगा?! इससे, कॉम्पोनेंट का आर्किटेक्चर मज़ेदार हो जाता है! पहले वर्शन में कौन अपने पसंदीदा फ़्रेमवर्क में स्लॉट शामिल करने वाला है? 🙂

चलिए, इसे अलग-अलग तरीके से समझें और वेब पर सभी के काम करने के तरीके सीखें. कोई Glitch बनाएं और उसका वर्शन मुझे ट्वीट करें. इसके बाद, मैं उसे नीचे दिए गए कम्यूनिटी रीमिक्स सेक्शन में जोड़ दूँगी.

कम्यूनिटी रीमिक्स