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

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

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

डेमो

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

आइकॉन

जब किसी पेज पर कोई आइकॉन दोहराया जाता है, तो एसवीजी <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.

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

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

नतीजा

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

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

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