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

रिस्पॉन्सिव स्लाइड बनाने के तरीके के बारे में खास जानकारी

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

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

खास जानकारी

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

डेस्कटॉप से मोबाइल के रिस्पॉन्सिव लेआउट का डेमो
iOS और Android के लिए, हल्के और गहरे रंग वाली थीम कम हो गई है

वेब रणनीति

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

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

मेरे समाधान में एक साइडबार है और सिर्फ़ तब टॉगल करता है, जब 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 में बदलाव और ट्रांज़िशन

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

  • खुला और बंद ऐनिमेट करें
  • मोशन के साथ ऐनिमेशन को सिर्फ़ तब ही ऐनिमेट करें, जब उपयोगकर्ता इससे सहमत हो
  • 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 पर फ़्लिप हो जाएगा.

सुलभता के लिए UX को बेहतर बनाया गया

इस समाधान के लिए, यूआरएल में बदलाव किया जाता है, ताकि राज्य को मैनेज किया जा सके. ज़ाहिर है कि यहां <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>
वॉइसओवर और कीबोर्ड इंटरैक्शन के UX का डेमो.

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

:is(:hover, :focus)

सीएसएस फ़ंक्शन वाले pseudo-selector से, हम अपनी होवर स्टाइल को फ़ोकस के साथ शेयर करके तेज़ी से उनमें शामिल हो पाते हैं.

.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() को कॉल करके ऐसा करता/करती हूं.

नतीजा

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

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

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