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

iOS और Android ऐप्लिकेशन में मौजूद टैब कॉम्पोनेंट की तरह ही टैब कॉम्पोनेंट बनाने का बुनियादी तरीका.

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

डेमो

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

खास जानकारी

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

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

यह कोलाज काफ़ी अस्त-व्यस्त है, क्योंकि वेब ने कॉम्पोनेंट के कॉन्सेप्ट में कई तरह की स्टाइल इस्तेमाल की हैं
पिछले 10 सालों में, टैब कॉम्पोनेंट के लिए वेब डिज़ाइन के स्टाइल का कोलाज

वेब रणनीतियां

कुल मिलाकर, मुझे यह कॉम्पोनेंट बनाने में काफ़ी आसानी हुई. इसकी वजह, वेब प्लैटफ़ॉर्म की कुछ अहम सुविधाएं हैं:

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

इसके बाद, मैंने लेखों में अलग-अलग लंबाई के लिंक और टाइटल के इमेज सेट के साथ-साथ अलग-अलग मात्रा में लोरम भरी. कॉन्टेंट के साथ काम करने के लिए, हम लेआउट शुरू कर सकते हैं.

स्क्रोल किए जा सकने वाले लेआउट

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

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

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

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

तीन स्क्रॉल वाले रंगीन डायग्राम पर वापस जाने के लिए:

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

nav और 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;
    }
  }
}

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

टैब हेडर <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;
  }
}

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

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

टैब <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;
}

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

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

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

तीन स्क्रोल एरिया का रीकैप

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

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

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

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

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

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

सुविधा से जुड़ी खास बातें

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

ऐनिमेशन

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

मैं लेख को स्क्रोल करने की जगह के साथ एक अंडरलाइन टैब जोड़ रहा हूं. स्नैपिंग का मतलब सिर्फ़ खूबसूरत अलाइनमेंट से नहीं है. यह ऐनिमेशन की शुरुआत और आखिर में भी ऐनकर होती है. इससे <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 पोज़िशन को डिस्ट्रक्चर करें और एक ऐसी स्ट्रिंग दिखाएं जो इसे 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 को एलान के तौर पर मैनेज कर सकती है. यह कभी-कभी यह छोटा सा मैच तैयार करता है.

नतीजा

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

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

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