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

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

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

डेमो

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

खास जानकारी

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

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

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

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

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

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

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

कलेक्शन

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

आइटम

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

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

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

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

लेआउट

मार्कअप

अच्छे कॉम्पोनेंट की शुरुआत सही एचटीएमएल से होती है. इस अगले सेक्शन में, मैं मार्कअप के विकल्पों और पूरे कॉम्पोनेंट पर उनके असर के बारे में बताऊँगी.

गहरे और हल्के रंग वाली थीम

<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 HTML को पढ़ता है, आइकॉन की जानकारी को मेमोरी में रखता है. साथ ही, आईडी का इस्तेमाल करने के लिए, पेज के बाकी बचे हिस्से को इस तरह से जारी रखता है:

<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> लिंक होगा. हालांकि, मैंने traversal 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 पर आगे और बीच में यह दिखेगा. एक एट्रिब्यूट कई लोगों को बटन का संदर्भ देता है.

एक स्क्रीनशॉट, जिसमें &#39;न दिखने वाले चुनने के एलिमेंट&#39; पर कर्सर घुमाया गया है और
उसका कॉन्टेक्स्ट के हिसाब से टूलटिप दिख रहा है.

सेपरेटर डेकोरेशन

<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 से विकल्प की पुष्टि नहीं की है. eager इवेंट, कॉम्पोनेंट की कैटगरी में बदलाव करने की सुविधा को ऐक्सेस नहीं कर सकता. इसकी वजह यह है कि चुनें बॉक्स खोलने और किसी आइटम को ब्राउज़ करने से, इवेंट ट्रिगर हो जाएगा और उपयोगकर्ता के तैयार होने से पहले पेज बदल जाएगा.

<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> एलिमेंट के इवेंट के ट्रिगर होने पर कॉम्पोनेंट, इंतज़ार या जाने का फ़ैसला ले सकता है.

नतीजा

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

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

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