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

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

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

डेमो

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

खास जानकारी

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

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

बैकग्राउंड का UX

ऊपर दिए गए कॉम्पोनेंट डेमो वीडियो में, प्लेसहोल्डर की कैटगरी, वीडियो गेम की शैलियां हैं. इस पगडंडी को नीचे दिए गए रास्ते पर नेविगेट करके बनाया गया है: 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 एचटीएमएल को पढ़ता है, आइकॉन की जानकारी को मेमोरी में सेव करता है, और आइकॉन के अन्य इस्तेमाल के लिए, आईडी का संदर्भ देने वाले पेज के बाकी हिस्से के साथ जारी रखता है, जैसे कि:

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

DevTools, रेंडर किए गए SVG के इस्तेमाल का एलिमेंट दिखा रहा है.

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

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

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

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

ओवरफ़्लो स्टाइल इन UX को सेट अप करती हैं:

  • ओवरस्क्रोल कंटेनमेंट के साथ हॉरिज़ॉन्टल स्क्रोलिंग.
  • हॉरिज़ॉन्टल स्क्रोल पैडिंग.
  • बचे हुए खाने के लिए एक स्नैप पॉइंट. इसका मतलब है कि पेज लोड होने पर, पहला क्रंब स्नैप किया गया और दिखता है.
  • 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 की मदद से उपयोगकर्ता अनुभव को बेहतर बनाने के लिए ये दो ज़रूरी उपाय हैं: चुने गए विकल्प ने <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> एलिमेंट के ट्रिगर होने पर इंतज़ार करने या जाने का फ़ैसला ले सकता है.

नतीजा

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

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

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