एक से ज़्यादा कॉम्पोनेंट चुनने की सुविधा का इस्तेमाल करना

उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, क्रम से लगाने और फ़िल्टर करने की सुविधा वाला रिस्पॉन्सिव, अडैप्टिव, और ऐक्सेस किया जा सकने वाला मल्टीसिलेक्ट कॉम्पोनेंट बनाने के तरीके के बारे में बुनियादी जानकारी.

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

डेमो

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

खास जानकारी

उपयोगकर्ताओं को अक्सर कई आइटम दिखाए जाते हैं. कभी-कभी तो बहुत सारे आइटम दिखाए जाते हैं. ऐसे मामलों में, सूची को छोटा करने का विकल्प देना एक अच्छा विचार हो सकता है, ताकि ज़्यादा विकल्प होने की वजह से उपयोगकर्ता भ्रमित न हों. इस ब्लॉग पोस्ट में, विकल्पों को कम करने के तरीके के तौर पर फ़िल्टर करने वाले यूज़र इंटरफ़ेस (यूआई) के बारे में बताया गया है. यह ऐसा इसलिए करता है, क्योंकि यह आइटम के ऐसे एट्रिब्यूट दिखाता है जिन्हें उपयोगकर्ता चुन या अनचुने कर सकते हैं. इससे खोज के नतीजे कम हो जाते हैं और इसलिए, विकल्पों की भरमार कम हो जाती है.

इंटरैक्शन

हमारा मकसद है कि सभी उपयोगकर्ता, फ़िल्टर के विकल्पों को आसानी से देख सकें. साथ ही, वे अलग-अलग तरह के इनपुट का इस्तेमाल कर सकें. यह अडैप्टिव और रिस्पॉन्सिव कॉम्पोनेंट के साथ डिलीवर किया जाएगा. डेस्कटॉप, कीबोर्ड, और स्क्रीन रीडर के लिए चेकबॉक्स वाला सामान्य साइडबार और टचस्क्रीन का इस्तेमाल करने वाले लोगों के लिए <select multiple>.

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

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

टच करके लॉक या अनलॉक करें

टच कॉम्पोनेंट से जगह बचती है. साथ ही, इससे मोबाइल पर उपयोगकर्ता के इंटरैक्शन को सटीक बनाने में मदद मिलती है. यह चेकबॉक्स के पूरे साइडबार को <select> बिल्ट-इन ओवरले टच अनुभव में छोटा करके जगह बचाता है. इससे इनपुट सटीक तरीके से दिया जा सकता है. इसके लिए, सिस्टम की ओर से उपलब्ध कराया गया बड़ा टच ओवरले दिखाया जाता है.

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

कीबोर्ड और गेमपैड

यहां कीबोर्ड से <select multiple> इस्तेमाल करने का तरीका बताया गया है.

इस सुविधा में, एक से ज़्यादा आइटम चुनने की सुविधा पहले से मौजूद होती है. हालांकि, इसे स्टाइल नहीं किया जा सकता. साथ ही, यह सिर्फ़ कॉम्पैक्ट लेआउट में उपलब्ध होती है. इसलिए, यह कई विकल्प दिखाने के लिए सही नहीं है. क्या आपको दिख रहा है कि उस छोटे बॉक्स में, विकल्पों की पूरी जानकारी नहीं दिख रही है? इसका साइज़ बदला जा सकता है. हालांकि, यह चेकबॉक्स वाले साइडबार की तरह इस्तेमाल में आसान नहीं है.

मार्कअप

दोनों कॉम्पोनेंट, एक ही <form> एलिमेंट में शामिल किए जाएंगे. इस फ़ॉर्म के नतीजों को देखा जाएगा और इनका इस्तेमाल ग्रिड को फ़िल्टर करने के लिए किया जाएगा. ये नतीजे, चेकबॉक्स या एक से ज़्यादा विकल्प चुनने वाले फ़ॉर्म के हो सकते हैं. हालांकि, इन्हें सर्वर पर भी सबमिट किया जा सकता है.

<form>

</form>

चेकबॉक्स कॉम्पोनेंट

चेकबॉक्स के ग्रुप को <fieldset> एलिमेंट में रैप किया जाना चाहिए और उन्हें <legend> दिया जाना चाहिए. एचटीएमएल को इस तरह से स्ट्रक्चर करने पर, स्क्रीन रीडर और FormData को एलिमेंट के बीच के संबंध के बारे में अपने-आप पता चल जाएगा.

<form>
  <fieldset>
    <legend>New</legend>
    … checkboxes …
  </fieldset>
</form>

ग्रुपिंग करने के बाद, हर फ़िल्टर के लिए <label> और <input type="checkbox"> जोड़ें. मैंने अपने लेबल को <div> में रैप किया है, ताकि सीएसएस gap प्रॉपर्टी, उन्हें बराबर दूरी पर रख सके. साथ ही, जब लेबल एक से ज़्यादा लाइन में जाते हैं, तब अलाइनमेंट बनाए रख सके.

<form>
  <fieldset>
    <legend>New</legend>
    <div>
      <input type="checkbox" id="last 30 days" name="new" value="last 30 days">
      <label for="last 30 days">Last 30 Days</label>
    </div>
    <div>
      <input type="checkbox" id="last 6 months" name="new" value="last 6 months">
      <label for="last 6 months">Last 6 Months</label>
    </div>
   </fieldset>
</form>

लेजेंड और फ़ील्डसेट एलिमेंट के लिए जानकारी देने वाले ओवरले का स्क्रीनशॉट. इसमें रंग और एलिमेंट का नाम दिखाया गया है.

<select multiple> कॉम्पोनेंट

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

<form>
  <select multiple="true" title="Filter results by category">
    …
  </select>
</form>

<select> में ग्रुप बनाने और उन्हें लेबल करने के लिए, <optgroup> एलिमेंट का इस्तेमाल करें. साथ ही, इसे label एट्रिब्यूट और वैल्यू दें. इस एलिमेंट और एट्रिब्यूट की वैल्यू, <fieldset> और <legend> एलिमेंट से मिलती-जुलती हैं.

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      …
    </optgroup>
  </select>
</form>

अब फ़िल्टर के लिए <option> एलिमेंट जोड़ें.

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      <option value="last 30 days">Last 30 Days</option>
      <option value="last 6 months">Last 6 Months</option>
    </optgroup>
  </select>
</form>

एक से ज़्यादा आइटम चुनने की सुविधा वाले एलिमेंट के डेस्कटॉप रेंडरिंग का स्क्रीनशॉट.

यह कुकी, काउंटर की मदद से इनपुट को ट्रैक करती है, ताकि सहायक टेक्नोलॉजी को इसकी जानकारी दी जा सके

इस उपयोगकर्ता अनुभव में, status role तकनीक का इस्तेमाल किया जाता है. इससे स्क्रीन रीडर और अन्य सहायक टेक्नोलॉजी के लिए, फ़िल्टर की संख्या को ट्रैक और बनाए रखने में मदद मिलती है. इस YouTube वीडियो में, सुविधा के बारे में बताया गया है. इंटिग्रेशन की शुरुआत एचटीएमएल और एट्रिब्यूट role="status" से होती है.

<div role="status" class="sr-only" id="applied-filters"></div>

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

aside {
  counter-reset: filters;
}

डिफ़ॉल्ट रूप से, गिनती 0 होगी, जो कि बहुत अच्छी बात है. इस डिज़ाइन में डिफ़ॉल्ट रूप से कुछ भी :checked नहीं है.

इसके बाद, नए काउंटर को बढ़ाने के लिए, हम <aside> एलीमेंट के उन चाइल्ड एलीमेंट को टारगेट करेंगे जो :checked हैं. उपयोगकर्ता के इनपुट की स्थिति बदलने पर, filters काउंटर में बदलाव होगा.

aside :checked {
  counter-increment: filters;
}

सीएसएस को अब चेकबॉक्स यूज़र इंटरफ़ेस (यूआई) के सामान्य टैली के बारे में पता है. साथ ही, स्टेटस रोल एलिमेंट खाली है और वैल्यू का इंतज़ार कर रहा है. CSS, मेमोरी में टैली को बनाए रखता है. इसलिए, counter() फ़ंक्शन, स्यूडो एलिमेंट के कॉन्टेंट से वैल्यू ऐक्सेस करने की अनुमति देता है:

aside #applied-filters::before {
  content: counter(filters) " filters ";
}

स्टेटस रोल एलिमेंट के लिए एचटीएमएल, अब स्क्रीन रीडर को "दो फ़िल्टर " के बारे में सूचना देगा. यह एक अच्छी शुरुआत है, लेकिन हम इसे और बेहतर बना सकते हैं. जैसे, फ़िल्टर से अपडेट किए गए नतीजों की संख्या शेयर करना. हम यह काम JavaScript से करेंगे, क्योंकि यह काउंटर की क्षमताओं से बाहर है.

MacOS के स्क्रीन रीडर का स्क्रीनशॉट. इसमें स्क्रीन रीडर, चालू फ़िल्टर की संख्या के बारे में बता रहा है.

नेस्टिंग के बारे में उत्साह

मुझे CSS nesting-1 के साथ काउंटर एल्गोरिदम का इस्तेमाल करके बहुत अच्छा लगा, क्योंकि मैं सभी लॉजिक को एक ब्लॉक में रख सका. इसे आसानी से कहीं भी ले जाया जा सकता है. साथ ही, इसे पढ़ने और अपडेट करने के लिए एक जगह पर रखा जा सकता है.

aside {
  counter-reset: filters;

  & :checked {
    counter-increment: filters;
  }

  & #applied-filters::before {
    content: counter(filters) " filters ";
  }
}

लेआउट

इस सेक्शन में, दोनों कॉम्पोनेंट के बीच के लेआउट के बारे में बताया गया है. लेआउट के ज़्यादातर स्टाइल, डेस्कटॉप चेकबॉक्स कॉम्पोनेंट के लिए होते हैं.

फ़ॉर्म

उपयोगकर्ताओं के लिए फ़ॉर्म को ज़्यादा से ज़्यादा 30 वर्णों की चौड़ाई दी गई है, ताकि वे इसे आसानी से पढ़ और स्कैन कर सकें. इससे हर फ़िल्टर लेबल के लिए ऑप्टिकल लाइन की चौड़ाई सेट हो जाती है. इस फ़ॉर्म में ग्रिड लेआउट और gap प्रॉपर्टी का इस्तेमाल किया गया है, ताकि फ़ील्डसेट के बीच में स्पेस दिया जा सके.

form {
  display: grid;
  gap: 2ch;
  max-inline-size: 30ch;
}

<select> एलिमेंट

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

@media (pointer: coarse) {
  select[multiple] {
    display: block;
  }
}

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

फ़ील्डसेट

<legend> के साथ <fieldset> की डिफ़ॉल्ट स्टाइल और लेआउट खास होता है:

फ़ील्डसेट और लेजेंड के लिए डिफ़ॉल्ट स्टाइल का स्क्रीनशॉट.

आम तौर पर, अपने चाइल्ड एलिमेंट के बीच स्पेस देने के लिए, मैं gap प्रॉपर्टी का इस्तेमाल करता हूं. हालांकि, <legend> की यूनीक पोज़िशनिंग की वजह से, चाइल्ड एलिमेंट के बीच एक जैसा स्पेस देना मुश्किल हो जाता है. gap के बजाय, adjacent sibling selector और margin-block-start का इस्तेमाल किया जाता है.

fieldset {
  padding: 2ch;

  & > div + div {
    margin-block-start: 2ch;
  }
}

इससे <legend> टैग के स्पेस को सिर्फ़ <div> चाइल्ड टैग को टारगेट करके अडजस्ट नहीं किया जाता.

इनपुट के बीच मार्जिन स्पेस दिखाने वाला स्क्रीनशॉट, लेकिन लेजेंड नहीं.

फ़िल्टर का लेबल और चेकबॉक्स

<fieldset> के डायरेक्ट चाइल्ड के तौर पर और फ़ॉर्म की ज़्यादा से ज़्यादा चौड़ाई 30ch के अंदर, लेबल का टेक्स्ट बहुत लंबा होने पर रैप हो सकता है. टेक्स्ट रैपिंग की सुविधा अच्छी है, लेकिन टेक्स्ट और चेकबॉक्स के बीच अलाइनमेंट सही नहीं है. इसके लिए, फ़्लेक्सबॉक्स सबसे सही है.

fieldset > div {
  display: flex;
  gap: 2ch;
  align-items: baseline;
}
इस स्क्रीनशॉट में दिखाया गया है कि कई लाइनों वाले टेक्स्ट के रैपिंग के उदाहरण में, सही का निशान टेक्स्ट की पहली लाइन के साथ कैसे अलाइन होता है.
इस Codepen में और खेलें

ऐनिमेटेड ग्रिड

लेआउट ऐनिमेशन, Isotope की मदद से किया जाता है. इंटरैक्टिव तरीके से क्रम से लगाने और फ़िल्टर करने के लिए, बेहतर परफ़ॉर्मेंस देने वाला और शक्तिशाली प्लगिन.

JavaScript

JavaScript का इस्तेमाल, ऐनिमेशन वाली इंटरैक्टिव ग्रिड को व्यवस्थित करने के साथ-साथ कुछ कमियों को ठीक करने के लिए भी किया जाता है.

उपयोगकर्ता के इनपुट को सामान्य बनाना

इस डिज़ाइन में एक फ़ॉर्म है, जिसमें इनपुट देने के दो अलग-अलग तरीके हैं. साथ ही, ये दोनों तरीके एक जैसे सीरियल नहीं होते. हालांकि, कुछ JavaScript की मदद से, हम डेटा को सामान्य कर सकते हैं.

DevTools JavaScript कंसोल का स्क्रीनशॉट. इसमें लक्ष्य और सामान्य किए गए डेटा के नतीजे दिख रहे हैं.

मैंने <select> एलिमेंट के डेटा स्ट्रक्चर को ग्रुप किए गए चेकबॉक्स के स्ट्रक्चर के साथ अलाइन करने का विकल्प चुना है. इसके लिए, <select> एलिमेंट में एक input इवेंट लिसनर जोड़ा जाता है. इसके बाद, selectedOptions को मैप किया जाता है.

document.querySelector('select').addEventListener('input', event => {
  // make selectedOptions iterable then reduce a new array object
  let selectData = Array.from(event.target.selectedOptions).reduce((data, opt) => {
    // parent optgroup label and option value are added to the reduce aggregator
    data.push([opt.parentElement.label.toLowerCase(), opt.value])
    return data
  }, [])
})

अब फ़ॉर्म सबमिट किया जा सकता है. इस डेमो में, Isotope को यह निर्देश दिया गया है कि किस आधार पर फ़िल्टर करना है.

स्टेटस रोल एलिमेंट को पूरा करना

यह एलिमेंट, सिर्फ़ चेकबॉक्स के साथ इंटरैक्शन के आधार पर फ़िल्टर की संख्या का हिसाब लगा रहा है और उसे दिखा रहा है. हालांकि, मुझे लगा कि नतीजों की संख्या को भी शेयर करना एक अच्छा विचार है. साथ ही, यह पक्का करना है कि <select> एलिमेंट के विकल्पों को भी गिना जाए.

<select> एलिमेंट को चुनने पर, counter() में बदलाव दिखना चाहिए

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

let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length

role="status" एलिमेंट में दिखने वाले नतीजे

:checked में, चुने गए फ़िल्टर की संख्या को स्टेटस रोल एलिमेंट में पास करने का एक इन-बिल्ट तरीका होता है. हालांकि, इसमें फ़िल्टर किए गए नतीजों की संख्या नहीं दिखती. JavaScript, चेकबॉक्स के साथ इंटरैक्शन को मॉनिटर कर सकती है. साथ ही, ग्रिड को फ़िल्टर करने के बाद, textContent जोड़ सकती है. यह <select> एलिमेंट की तरह काम करता है.

document
  .querySelector('aside form')
  .addEventListener('input', e => {
    // isotope demo code
    let filterResults = IsotopeGrid.getFilteredItemElements().length
    document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})

इस तरह, "25 नतीजे दिखाने वाले दो फ़िल्टर" वाली सूचना पूरी हो जाती है.

MacOS के स्क्रीन रीडर के नतीजों को बोलकर सुनाने का स्क्रीनशॉट.

अब हमारी बेहतरीन ऐक्सेसिबिलिटी टेक्नोलॉजी का अनुभव सभी उपयोगकर्ताओं को मिलेगा, भले ही वे इसका इस्तेमाल किसी भी तरह से करें.

नतीजा

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

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

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

अभी यहां देखने के लिए कुछ नहीं है!