उपयोगकर्ता अनुभव को क्रम से लगाने और फ़िल्टर करने के लिए, रिस्पॉन्सिव, अडैप्टिव, और ऐक्सेस किए जा सकने वाले मल्टी-सिलेक्ट कॉम्पोनेंट बनाने का बुनियादी तरीका.
इस पोस्ट में, मैं एक से ज़्यादा आइटम चुनने की सुविधा देने वाले कॉम्पोनेंट को बनाने का तरीका शेयर करना चाहता हूं. डेमो आज़माएं.
अगर आपको वीडियो देखना पसंद है, तो यहां इस पोस्ट का YouTube वर्शन दिया गया है:
खास जानकारी
उपयोगकर्ताओं को अक्सर आइटम दिखाए जाते हैं. कभी-कभी, बहुत आइटम दिखाए जाते हैं. ऐसे में, सूची को छोटा करने का तरीका उपलब्ध कराना एक अच्छा विचार हो सकता है, ताकि ज़्यादा विकल्पों से उपयोगकर्ताओं को परेशानी न हो. इस ब्लॉग पोस्ट में, विकल्पों को कम करने के लिए यूज़र इंटरफ़ेस (यूआई) को फ़िल्टर करने के बारे में बताया गया है. यह ऐसा करके करता है कि आइटम के ऐसे एट्रिब्यूट दिखाए जाएं जिन्हें उपयोगकर्ता चुन या हटा सकते हैं. इससे नतीजों की संख्या कम हो जाती है और उपयोगकर्ताओं को बहुत ज़्यादा विकल्प नहीं मिलते.
इंटरैक्शन
इसका मकसद, सभी उपयोगकर्ताओं और उनके अलग-अलग इनपुट टाइप के लिए, फ़िल्टर के विकल्पों को तेज़ी से ट्रैवर्स करने की सुविधा चालू करना है. इसे अडैप्ट करने लायक और रिस्पॉन्सिव कॉम्पोनेंट के साथ डिलीवर किया जाएगा. डेस्कटॉप, कीबोर्ड, और स्क्रीन रीडर के लिए चेकबॉक्स वाला पारंपरिक साइडबार. साथ ही, टच का इस्तेमाल करने वाले लोगों के लिए <select
multiple>
.
टच के लिए पहले से मौजूद मल्टी-सिलेक्ट का इस्तेमाल करने और डेस्कटॉप के लिए नहीं करने का यह फ़ैसला, काम को आसान बनाता है और काम बढ़ाता है. हालांकि, मेरा मानना है कि एक कॉम्पोनेंट में पूरा रिस्पॉन्सिव अनुभव बनाने के बजाय, कम कोड डेट के साथ सही अनुभव मिलता है.
छूकर
टच कॉम्पोनेंट से जगह बचती है और मोबाइल पर उपयोगकर्ता के इंटरैक्शन को सटीक बनाने में मदद मिलती है. यह चेकबॉक्स के पूरे साइडबार को <select>
में पहले से मौजूद ओवरले टच अनुभव में छोटा करके जगह बचाता है. यह सिस्टम की मदद से, बड़ा टच ओवरले दिखाकर, सटीक इनपुट करने में मदद करता है.
कीबोर्ड और गेमपैड
कीबोर्ड से <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>
सहायता वाली टेक्नोलॉजी को जानकारी देने के लिए, काउंटर की मदद से इनपुट ट्रैक करना
इस यूज़र एक्सपीरियंस में, स्टेटस की भूमिका वाली तकनीक का इस्तेमाल किया जाता है. इससे स्क्रीन रीडर और अन्य सहायक टेक्नोलॉजी के लिए, फ़िल्टर की संख्या को ट्रैक और मैनेज किया जा सकता है. YouTube वीडियो में इस सुविधा के बारे में बताया गया है. इंटिग्रेशन, एचटीएमएल और एट्रिब्यूट role="status"
से शुरू होता है.
<div role="status" class="sr-only" id="applied-filters"></div>
यह एलिमेंट, कॉन्टेंट में किए गए बदलावों को ज़ोर से पढ़कर सुनाएगा. जब उपयोगकर्ता चेकबॉक्स के साथ इंटरैक्ट करते हैं, तो हम सीएसएस काउंटर की मदद से कॉन्टेंट को अपडेट कर सकते हैं. इसके लिए, हमें सबसे पहले इनपुट और स्टेटस एलिमेंट के पैरंट एलिमेंट पर, नाम वाला एक काउंटर बनाना होगा.
aside {
counter-reset: filters;
}
डिफ़ॉल्ट रूप से, गिनती 0
होगी, जो बहुत बढ़िया है. इस डिज़ाइन में डिफ़ॉल्ट रूप से कुछ भी 0
नहीं होता.:checked
इसके बाद, अपने नए बनाए गए काउंटर को बढ़ाने के लिए, हम <aside>
एलिमेंट के उन चाइल्ड एलिमेंट को टारगेट करेंगे जो :checked
हैं. जब उपयोगकर्ता इनपुट की स्थिति बदलता है, तो filters
काउंटर बढ़ता जाएगा.
aside :checked {
counter-increment: filters;
}
सीएसएस को अब चेकबॉक्स यूज़र इंटरफ़ेस (यूआई) की सामान्य गिनती के बारे में पता है. साथ ही, स्थिति की भूमिका वाला एलिमेंट खाली है और वैल्यू का इंतज़ार कर रहा है. सीएसएस, गिनती को मेमोरी में सेव रखती है. इसलिए, counter()
फ़ंक्शन की मदद से, स्यूडो एलिमेंट कॉन्टेंट की वैल्यू को ऐक्सेस किया जा सकता है:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
स्टेटस की भूमिका वाले एलिमेंट के एचटीएमएल से, अब स्क्रीन रीडर को "दो फ़िल्टर " का एलान किया जाएगा. यह एक अच्छी शुरुआत है, लेकिन हम और भी बेहतर कर सकते हैं. जैसे, फ़िल्टर की मदद से अपडेट किए गए नतीजों की संख्या शेयर करना. हम यह काम JavaScript से करेंगे, क्योंकि यह काउंटर के दायरे से बाहर है.
नेस्टिंग एक्साइटमेंट
सीएसएस नेस्टिंग-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
के बजाय, आस-पास के सिबलिंग सिलेक्टर और 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;
}

ऐनिमेटेड ग्रिड
लेआउट ऐनिमेशन, Isotope की मदद से किया जाता है. इंटरैक्टिव क्रम से लगाने और फ़िल्टर करने के लिए, बेहतर परफ़ॉर्म करने वाला और बेहतरीन प्लग इन.
JavaScript
बेहतर ऐनिमेशन और इंटरैक्टिव ग्रिड बनाने के अलावा, JavaScript का इस्तेमाल कुछ और कामों के लिए भी किया जाता है.
उपयोगकर्ता के इनपुट को सामान्य करना
इस डिज़ाइन में एक फ़ॉर्म है, जिसमें इनपुट देने के दो अलग-अलग तरीके हैं. साथ ही, इनमें एक जैसे डेटा को सीरियलाइज़ नहीं किया जाता. हालांकि, कुछ 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, चेकबॉक्स के साथ इंटरैक्शन को देख सकता है और ग्रिड को फ़िल्टर करने के बाद, <select>
एलिमेंट की तरह textContent
जोड़ सकता है.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
इस काम से, "दो फ़िल्टर से 25 नतीजे मिलते हैं" एलान पूरा हो जाता है.
अब सभी उपयोगकर्ताओं को, सहायता वाली टेक्नोलॉजी का बेहतरीन अनुभव मिलेगा. भले ही, वे इस टेक्नोलॉजी के साथ किसी भी तरह से इंटरैक्ट करें.
नतीजा
अब आपको पता है कि मैंने यह कैसे किया, तो आप कैसे करेंगे‽ 🙂
आइए, अलग-अलग तरीकों का इस्तेमाल करके, वेब पर कॉन्टेंट बनाने के सभी तरीके जानें. डेमो बनाएं और मुझे ट्वीट करें लिंक भेजें. हम इसे कम्यूनिटी रीमिक्स सेक्शन में जोड़ देंगे!
कम्यूनिटी रीमिक्स
अभी यहां देखने के लिए कुछ नहीं है!