साइडनेव कॉम्पोनेंट बनाना

रिस्पॉन्सिव स्लाइड आउट साइडनेव बनाने के तरीके के बारे में बुनियादी जानकारी

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

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

खास जानकारी

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

डेस्कटॉप से मोबाइल पर काम करने वाले लेआउट का डेमो
iOS और Android पर लाइट और डार्क थीम का इस्तेमाल करना

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

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

  1. सीएसएस :target
  2. सीएसएस ग्रिड
  3. सीएसएस के बदलाव
  4. व्यूपोर्ट और उपयोगकर्ता की प्राथमिकता के लिए सीएसएस मीडिया क्वेरी
  5. focus यूएक्स को बेहतर बनाने के लिए JS

मेरे समाधान में एक साइडबार है और यह सिर्फ़ तब टॉगल होता है, जब "मोबाइल" व्यूपोर्ट 540px या उससे कम हो. मोबाइल इंटरैक्टिव लेआउट और स्टैटिक डेस्कटॉप लेआउट के बीच स्विच करने के लिए, 540px हमारा ब्रेकपॉइंट होगा.

सीएसएस :target pseudo-class

एक <a> लिंक, यूआरएल हैश को #sidenav-open पर सेट करता है और दूसरा लिंक उसे खाली ('') पर सेट करता है. आखिर में, हैश से मैच करने के लिए एलिमेंट में id होता है:

<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<aside id="sidenav-open">
  …
</aside>

इनमें से हर लिंक पर क्लिक करने से हमारे पेज के यूआरएल की हैश स्थिति बदल जाती है, फिर एक pseudo-class जैसे कि साइडनेव को दिखाया और छिपाया जाता है:

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
  }

  #sidenav-open:target {
    visibility: visible;
  }
}

सीएसएस ग्रिड

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

स्टैक

प्राइमरी लेआउट एलिमेंट #sidenav-container एक ग्रिड होता है, जो एक लाइन और दो कॉलम बनाता है. इनमें से हर एक का नाम stack होता है. जगह की कमी होने पर सीएसएस, <main> एलिमेंट के सभी बच्चों को एक ही ग्रिड नाम असाइन करता है. इस तरह, सभी एलिमेंट को एक ही स्पेस में रखा जाता है और एक स्टैक बन जाता है.

#sidenav-container {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;
  min-height: 100vh;
}

@media (max-width: 540px) {
  #sidenav-container > * {
    grid-area: stack;
  }
}

<aside>, ऐनिमेशन वाला एलिमेंट है, जिसमें साइड नेविगेशन शामिल होता है. इसमें 2 बच्चे हैं: नेविगेशन कंटेनर <nav>, जिसका नाम [nav] है और एक बैकग्राउंड <a> है, जिसका नाम [escape] है. इसका इस्तेमाल मेन्यू को बंद करने के लिए किया जाता है.

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

2fr और 1fr को अडजस्ट करके, मेन्यू ओवरले और इसके नेगेटिव स्पेस को बंद करने वाले बटन के लिए पसंदीदा अनुपात चुनें.

अनुपात बदलने पर क्या होता है, इसका डेमो.

सीएसएस 3D ट्रांसफ़ॉर्म और ट्रांज़िशन

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

  • खुला और बंद ऐनिमेट करें
  • सिर्फ़ तब ऐनिमेशन दिखाएं, जब उपयोगकर्ता को इसकी अनुमति हो
  • visibility को ऐनिमेट करें, ताकि कीबोर्ड फ़ोकस, ऑफ़स्क्रीन एलिमेंट में न जाए

मोशन ऐनिमेशन लागू करने के दौरान, मैं सुलभता को सबसे ज़्यादा अहमियत दूंगा.

ऐक्सेस करने लायक मोशन

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

#sidenav-open {
  --duration: .6s;
}

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
इंटरैक्शन का डेमो, जिसमें दिखने की अवधि लागू है और नहीं है.

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

ट्रांज़िशन, ट्रांसफ़ॉर्म, अनुवाद

साइडनेव आउट (डिफ़ॉल्ट)

मोबाइल पर साइडनेव की डिफ़ॉल्ट स्थिति को ऑफ़स्क्रीन पर सेट करने के लिए, मैं एलिमेंट को transform: translateX(-110vw) के साथ पोज़िशन करता/करती हूं.

ध्यान दें, मैंने -100vw के सामान्य ऑफ़स्क्रीन कोड में एक और 10vw जोड़ा है, ताकि यह पक्का किया जा सके कि साइडनेव के box-shadow को छिपाने पर, वह मुख्य व्यूपोर्ट में न दिखे.

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);
  }
}
साइडनेव इन

जब #sidenav एलिमेंट, :target के तौर पर मैच होता है, तो translateX() पोज़िशन को होमबेस 0 पर सेट करें. साथ ही, देखें कि यूआरएल हैश बदलने पर, सीएसएस एलिमेंट को -110vw की आउट पोज़िशन से, var(--duration) की "इन" पोज़िशन पर 0 तक कैसे स्लाइड करती है.

@media (max-width: 540px) {
  #sidenav-open:target {
    visibility: visible;
    transform: translateX(0);
    transition:
      transform var(--duration) var(--easeOutExpo);
  }
}

ट्रांज़िशन दिखने की सेटिंग

अब हमारा मकसद, स्क्रीन रीडर से मेन्यू को छिपाना है, ताकि सिस्टम किसी ऑफ़स्क्रीन मेन्यू पर फ़ोकस न कर सकें. ऐसा करने के लिए, :target के बदलने पर, दिखने की स्थिति में बदलाव करने का ट्रांज़िशन सेट किया जाता है.

  • अंदर जाते समय, एलिमेंट को तुरंत दिखाएं, न कि धीरे-धीरे. इससे मुझे एलिमेंट को स्लाइड करते हुए देखने और उस पर फ़ोकस करने में मदद मिलेगी.
  • बाहर जाते समय, ट्रांज़िशन के दिखने पर रोक लगाएं, लेकिन थोड़ा इंतज़ार करें. इसलिए, ट्रांज़िशन खत्म होने के बाद, यह hidden पर फ़्लिप हो जाएगा.

सुलभता से जुड़े यूज़र एक्सपीरियंस को बेहतर बनाना

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

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
  <svg>...</svg>
</a>
वॉइसओवर और कीबोर्ड इंटरैक्शन यूएक्स का डेमो.

अब हमारे प्राइमरी इंटरैक्शन बटन, माउस और कीबोर्ड, दोनों के लिए साफ़ तौर पर अपने इंटेंट के बारे में बताते हैं.

:is(:hover, :focus)

सीएसएस फ़ंक्शनल स्यूडो-सिलेक्टर की मदद से, हम फ़ोकस के साथ-साथ कर्सर घुमाने पर दिखने वाली स्टाइल को भी आसानी से शामिल कर सकते हैं.

.hamburger:is(:hover, :focus) svg > line {
  stroke: hsl(var(--brandHSL));
}

JavaScript पर स्प्रिंकल करें

बंद करने के लिए escape दबाएं

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

const sidenav = document.querySelector('#sidenav-open');

sidenav.addEventListener('keyup', event => {
  if (event.code === 'Escape') document.location.hash = '';
});
ब्राउज़र इतिहास

ब्राउज़र के इतिहास में, खोलने और बंद करने के इंटरैक्शन से कई एंट्री स्टैक होने से रोकने के लिए, बंद करें बटन में यह JavaScript इनलाइन जोड़ें:

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>

ऐसा करने से यूआरएल इतिहास की एंट्री बंद हो जाएगी, जिससे ऐसा लगेगा जैसे मेन्यू कभी खोला ही नहीं गया था.

उपयोगकर्ता अनुभव पर फ़ोकस करें

अगले स्निपेट से, हमें यह पता चलता है कि स्क्रीन खुलने या बंद होने के बाद, खोलने और बंद करने के बटन पर फ़ोकस कैसे किया जाता है. मुझे टॉगल करने की सुविधा को आसान बनाना है.

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

साइडनेवि खोलने पर, बंद करने के बटन पर फ़ोकस करें. साइडनेव बंद होने पर, 'खोलें' बटन पर फ़ोकस करें. मैं ऐसा JavaScript में एलिमेंट पर focus() कॉल करके करता/करती हूं.

नतीजा

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

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

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