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

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

इस पोस्ट में, मैं ब्रेडक्रंब कॉम्पोनेंट बनाने के तरीके के बारे में बताना चाहता हूं. डेमो देखें.

डेमो

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

खास जानकारी

ब्रेडक्रंब कॉम्पोनेंट से पता चलता है कि उपयोगकर्ता साइट के किस क्रम में है. इसका नाम हैंसल और ग्रेटल ने रखा है. इन्होंने ब्रेडक्रंब को पीछे की ओर ट्रेस करके, अपने पीछे किसी गहरे रंग के जंगल में ब्रेडक्रंब डाले थे.

इस पोस्ट में ब्रेडक्रंब, स्टैंडर्ड ब्रेडक्रंब नहीं हैं. ये ब्रेडक्रंब जैसे हैं. ये <select> के साथ नेविगेशन में, मिलते-जुलते पेजों को डालकर अतिरिक्त सुविधाएं देते हैं. इससे, कई लेवल का ऐक्सेस मिलता है.

बैकग्राउंड यूएक्स

ऊपर दिए गए कॉम्पोनेंट के डेमो वीडियो में, प्लेसहोल्डर कैटगरी में वीडियो गेम की शैलियां हैं. यह ट्रेल, यहां दिए गए पाथ पर जाकर बनाया जाता है: home » rpg » indie » on sale, जैसा कि यहां दिखाया गया है.

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

इन्फ़ॉर्मेशन आर्किटेक्चर

मुझे लगता है कि संग्रह और आइटम के हिसाब से सोचना मददगार होता है.

कलेक्शन

कलेक्शन, विकल्पों का एक कलेक्शन होता है. इस पोस्ट के ब्रेडक्रंब प्रोटोटाइप के होम पेज पर, एफ़पीएस, आरपीजी, ब्रॉलर, डंगऑन क्रॉलर, स्पोर्ट्स, और पहेली वाले कलेक्शन मौजूद हैं.

आइटम

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

कंप्यूटर साइंस के हिसाब से, यह ब्रेडक्रंब कॉम्पोनेंट एक मल्टीडाइमेंशनल ऐरे दिखाता है:

const rawBreadcrumbData = {
  "FPS": {...},
  "RPG": {
    "AAA": {...},
    "indie": {
      "new": {...},
      "on sale": {...},
      "under 5": {...},
    },
    "self published": {...},
  },
  "brawler": {...},
  "dungeon crawler": {...},
  "sports": {...},
  "puzzle": {...},
}

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

लेआउट

मार्कअप

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

डार्क और लाइट स्कीम

<meta name="color-scheme" content="dark light">

ऊपर दिए गए स्निपेट में मौजूद color-scheme मेटा टैग, ब्राउज़र को बताता है कि इस पेज को ब्राउज़र के लाइट और डार्क स्टाइल चाहिए. ब्रेडक्रंब के उदाहरण में, इन कलर स्कीम के लिए कोई सीएसएस शामिल नहीं है. इसलिए, ब्रेडक्रंब ब्राउज़र के डिफ़ॉल्ट रंगों का इस्तेमाल करेंगे.

<nav class="breadcrumbs" role="navigation"></nav>

साइट नेविगेशन के लिए, <nav> एलिमेंट का इस्तेमाल करना सही होता है. इसमें, ARIA नेविगेशन की भूमिका पहले से तय होती है. जांच के दौरान, मुझे पता चला कि role एट्रिब्यूट की वजह से, स्क्रीन रीडर ने एलिमेंट के साथ इंटरैक्ट करने का तरीका बदल दिया. असल में, इसे नेविगेशन के तौर पर पढ़ा गया. इसलिए, मैंने इसे जोड़ने का विकल्प चुना है.

आइकॉन

जब किसी पेज पर कोई आइकॉन दोहराया जाता है, तो SVG <use> एलिमेंट का मतलब है कि path को एक बार तय किया जा सकता है और इसका इस्तेमाल आइकॉन के सभी इंस्टेंस के लिए किया जा सकता है. इससे पाथ की एक ही जानकारी को बार-बार होने से रोका जा सकता है. इससे बड़े दस्तावेज़ बड़े हो सकते हैं और पाथ एक जैसा नहीं हो सकता.

इस तकनीक का इस्तेमाल करने के लिए, पेज में एक छिपा हुआ SVG एलिमेंट जोड़ें और यूनीक आईडी वाले <symbol> एलिमेंट में आइकॉन को रैप करें:

<svg style="display: none;">

  <symbol id="icon-home">
    <title>A home icon</title>
    <path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
  </symbol>

  <symbol id="icon-dropdown-arrow">
    <title>A down arrow</title>
    <path d="M19 9l-7 7-7-7"/>
  </symbol>

</svg>

ब्राउज़र, एसवीजी एचटीएमएल को पढ़ता है और आइकॉन की जानकारी को मेमोरी में सेव करता है. इसके बाद, वह आइकॉन के अन्य इस्तेमाल के लिए, आईडी का रेफ़रंस देकर पेज के बाकी हिस्से को पढ़ता है. जैसे:

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-home" />
</svg>

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-dropdown-arrow" />
</svg>

रेंडर किए गए SVG का इस्तेमाल करने वाले एलिमेंट को दिखाने वाले DevTools.

एक बार तय करें और जितनी बार चाहें उतनी बार इस्तेमाल करें. इससे पेज की परफ़ॉर्मेंस पर कम से कम असर पड़ता है और स्टाइल में बदलाव करने की सुविधा मिलती है. सूचना aria-hidden="true" को SVG एलिमेंट में जोड़ा गया है. आइकॉन ब्राउज़ करने वाले किसी ऐसे व्यक्ति के लिए उपयोगी नहीं होते हैं जिसे सिर्फ़ कॉन्टेंट सुनाई देता है. इन आइकॉन को उपयोगकर्ताओं से छिपाने से वे ग़ैर-ज़रूरी आवाज़ नहीं जोड़ते हैं.

यहीं पर पारंपरिक ब्रेडक्रंब और इस कॉम्पोनेंट में मौजूद ब्रेडक्रंब अलग-अलग होते हैं. आम तौर पर, यह सिर्फ़ <a> लिंक होगा, लेकिन मैंने ट्रैवर्सल UX को उस विकल्प के साथ जोड़ा है जिसे छिपाया गया है. .crumb क्लास, लिंक और आइकॉन को लेआउट करने के लिए ज़िम्मेदार है. वहीं, .crumbicon क्लास, आइकॉन और चुने गए एलिमेंट को एक साथ स्टैक करने के लिए ज़िम्मेदार है. मैंने इसे स्प्लिट-लिंक कहा है, क्योंकि इसके फ़ंक्शन स्प्लिट-बटन से काफ़ी मिलते-जुलते हैं, लेकिन ये पेज नेविगेशन के लिए होते हैं.

<span class="crumb">
  <a href="#sub-collection-b">Category B</a>
  <span class="crumbicon">
    <svg>...</svg>
    <select class="disguised-select" title="Navigate to another category">
      <option>Category A</option>
      <option selected>Category B</option>
      <option>Category C</option>
    </select>
  </span>
</span>

लिंक और कुछ विकल्पों का होना कोई खास बात नहीं है. हालांकि, इससे सामान्य ब्रेडक्रंब में ज़्यादा फ़ंक्शन जुड़ जाते हैं. <select> एलिमेंट में title जोड़ने से, स्क्रीन रीडर इस्तेमाल करने वाले लोगों को बटन की कार्रवाई के बारे में जानकारी मिलती है. हालांकि, यह सुविधा सभी लोगों के लिए उपलब्ध है. आपको iPad पर यह सुविधा सबसे ऊपर दिखेगी. एक एट्रिब्यूट, कई उपयोगकर्ताओं को बटन का कॉन्टेक्स्ट उपलब्ध कराता है.

स्क्रीनशॉट में दिख रहे ऐसे एलिमेंट को घुमाया जा रहा है जो दिख नहीं रहा है और
काम के हिसाब से टूलटिप दिख रहा है.

सेपरेटर की सजावट

<span class="crumb-separator" aria-hidden="true">→</span>

सेपरेटर का इस्तेमाल करना ज़रूरी नहीं है. एक ही जोड़ने से बहुत अच्छी तरह काम होता है (ऊपर दिए गए वीडियो में तीसरा उदाहरण देखें). इसके बाद, मैं हर aria-hidden="true" को एक एलिमेंट के तौर पर लेता हूं, क्योंकि स्क्रीन रीडर को इनकी जानकारी नहीं देनी होती.

अगले लेख में बताई गई gap प्रॉपर्टी की मदद से, इनके बीच आसानी से स्पेसिंग की जा सकती है.

स्टाइल

रंग में सिस्टम के रंगों का इस्तेमाल किया जाता है. इसलिए, इसमें स्टाइल के लिए ज़्यादातर गैप और स्टैक होते हैं!

लेआउट की दिशा और फ़्लो

DevTools, फ़्लेक्सबॉक्स ओवरले की सुविधा के साथ ब्रेडक्रंब नेविगेशन अलाइनमेंट दिखा रहा है.

मुख्य नेविगेशन एलिमेंट nav.breadcrumbs, बच्चों के इस्तेमाल के लिए स्कोप वाली कस्टम प्रॉपर्टी सेट करता है. इसके अलावा, यह वर्टिकल अलाइन किए गए हॉरिज़ॉन्टल लेआउट को भी सेट करता है. इससे यह पक्का होता है कि क्रंब, डिवाइडर, और आइकॉन अलाइन हों.

.breadcrumbs {
  --nav-gap: 2ch;

  display: flex;
  align-items: center;
  gap: var(--nav-gap);
  padding: calc(var(--nav-gap) / 2);
}

एक ब्रेडक्रंब, जिसे फ़्लेक्सबॉक्स ओवरले के साथ वर्टिकल अलाइन किया गया है.

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

.crumb {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--nav-gap) / 4);

  & > a {
    white-space: nowrap;

    &[aria-current="page"] {
      font-weight: bold;
    }
  }
}

aria-current="page" को जोड़ा गया है, ताकि मौजूदा पेज का लिंक बाकी पेजों से अलग दिखे. स्क्रीन रीडर का इस्तेमाल करने वाले लोगों को यह साफ़ तौर पर पता चल जाएगा कि लिंक मौजूदा पेज के लिए है. साथ ही, हमने एलिमेंट को विज़ुअल स्टाइल दिया है, ताकि सामान्य उपयोगकर्ताओं को भी एक जैसा अनुभव मिल सके.

.crumbicon कॉम्पोनेंट, "लगभग अदृश्य" <select> एलिमेंट के साथ SVG आइकॉन को स्टैक करने के लिए ग्रिड का इस्तेमाल करता है.

ग्रिड डेवलपर टूल, बटन पर ओवरले किए गए ऐसे ग्रिड को दिखाता है जिसमें पंक्ति और कॉलम, दोनों का नाम स्टैक है.

.crumbicon {
  --crumbicon-size: 3ch;

  display: grid;
  grid: [stack] var(--crumbicon-size) / [stack] var(--crumbicon-size);
  place-items: center;

  & > * {
    grid-area: stack;
  }
}

<select> एलिमेंट, डीओएम में आखिरी होता है. इसलिए, यह स्टैक में सबसे ऊपर है और इंटरैक्टिव है. opacity: .01 की स्टाइल जोड़ें, ताकि एलिमेंट को अब भी इस्तेमाल किया जा सके. इससे आपको एक बॉक्स मिलेगा, जो आइकॉन के आकार में पूरी तरह फ़िट हो जाएगा. यह <select> एलिमेंट के दिखने के तरीके को पसंद के मुताबिक बनाने का एक अच्छा तरीका है. ऐसा करने पर, एलिमेंट में पहले से मौजूद फ़ंक्शन काम करते रहेंगे.

.disguised-select {
  inline-size: 100%;
  block-size: 100%;
  opacity: .01;
  font-size: min(100%, 16px); /* Defaults to 16px; fixes iOS zoom */
}

ओवरफ़्लो

ब्रेडक्रंब में बहुत लंबा ट्रेल दिखना चाहिए. मैं ज़रूरत पड़ने पर, चीज़ों को हॉरिज़ॉन्टल तौर पर स्क्रीन से बाहर जाने की अनुमति देने का समर्थक हूं. मुझे लगता है कि ब्रेडक्रंब कॉम्पोनेंट के लिए यह सही है.

.breadcrumbs {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: calc(var(--nav-gap) / 2);

  & > .crumb:last-of-type {
    scroll-snap-align: end;
  }

  @supports (-webkit-hyphens:none) { & {
    scroll-snap-type: none;
  }}
}

ओवरफ़्लो स्टाइल, इस यूज़र एक्सपीरियंस को सेट अप करते हैं:

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

मीडिया क्वेरी

छोटे व्यूपोर्ट के लिए, "होम" लेबल को छिपाकर सिर्फ़ आइकॉन को दिखाया जा सकता है:

@media (width <= 480px) {
  .breadcrumbs .home-label {
    display: none;
  }
}

तुलना के लिए, होम लेबल के साथ और उसके बिना ब्रेडक्रंब को अगल-बगल दिखाया गया है.

सुलभता

मोशन

इस कॉम्पोनेंट में बहुत ज़्यादा मोशन नहीं है, लेकिन ट्रांज़िशन को prefers-reduced-motion जांच में लपेटकर, हम अनचाहे मोशन को रोक सकते हैं.

@media (prefers-reduced-motion: no-preference) {
  .crumbicon {
    transition: box-shadow .2s ease;
  }
}

बाकी किसी भी स्टाइल को बदलने की ज़रूरत नहीं होती. transition के बिना, कर्सर घुमाने और फ़ोकस करने से जुड़े इफ़ेक्ट बहुत अच्छे और सही होते हैं. अगर मोशन ठीक है, तो हम इंटरैक्शन में एक छोटा सा ट्रांज़िशन जोड़ देंगे.

JavaScript

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

JavaScript, उपयोगकर्ता अनुभव के दो अहम मेज़र को मैनेज करता है: has changed चुनें और इग़र <select> बदलाव इवेंट ट्रिगर होने से रोकना.

<select> एलिमेंट का इस्तेमाल करने की वजह से, उत्सुक इवेंट को रोकने की ज़रूरत होती है. Windows Edge और शायद अन्य ब्राउज़र पर भी, जब उपयोगकर्ता कीबोर्ड से विकल्पों को ब्राउज़ करता है, तो चुनें changed इवेंट ट्रिगर होता है. इसलिए, मैंने इसे उत्सुकता से चुना गया विकल्प कहा है, क्योंकि उपयोगकर्ता ने विकल्प को सिर्फ़ हॉवर या फ़ोकस करने जैसी कार्रवाई करके चुना है. हालांकि, उसने enter या click का इस्तेमाल करके, विकल्प की पुष्टि नहीं की है. इग़र इवेंट की वजह से, इस कॉम्पोनेंट की कैटगरी बदलने की सुविधा का इस्तेमाल नहीं किया जा सकता. ऐसा इसलिए है, क्योंकि चुनने के लिए दिए गए बॉक्स को खोलने और किसी आइटम को ब्राउज़ करने से, इवेंट ट्रिगर हो जाएगा और उपयोगकर्ता के तैयार होने से पहले ही पेज बदल जाएगा.

बेहतर <select> बदला गया इवेंट

const crumbs = document.querySelectorAll('.breadcrumbs select')
const allowedKeys = new Set(['Tab', 'Enter', ' '])
const preventedKeys = new Set(['ArrowUp', 'ArrowDown'])

// watch crumbs for changes,
// ensures it's a full value change, not a user exploring options via keyboard
crumbs.forEach(nav => {
  let ignoreChange = false

  nav.addEventListener('change', e => {
    if (ignoreChange) return
    // it's actually changed!
  })

  nav.addEventListener('keydown', ({ key }) => {
    if (preventedKeys.has(key))
      ignoreChange = true
    else if (allowedKeys.has(key))
      ignoreChange = false
  })
})

इसके लिए, हर <select> एलिमेंट पर कीबोर्ड के दबाए जाने से जुड़े इवेंट देखे जाते हैं. साथ ही, यह तय किया जाता है कि दबाया गया बटन, नेविगेशन की पुष्टि (Tab या Enter) या स्पेस नेविगेशन (ArrowUp या ArrowDown) के लिए था या नहीं. इस जानकारी के आधार पर, <select> एलिमेंट के इवेंट ट्रिगर होने पर, कॉम्पोनेंट इंतज़ार करने या आगे बढ़ने का फ़ैसला ले सकता है.

नतीजा

अब आपको पता है कि मैंने यह कैसे किया, तो आप कैसे करेंगे‽ 🙂

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

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