نظرة عامة أساسية حول كيفية إنشاء مكوّن اختيار متعدّد متجاوب وتكيُّفي ويمكن الوصول إليه لتوفير تجارب مستخدمين تتيح لهم التصنيف والفلترة
في هذه المشاركة، أريد أن أشارك أفكارًا حول طريقة إنشاء مكوّن اختيار متعدّد. جرِّب العرض التوضيحي.
إذا كنت تفضّل مشاهدة فيديو، إليك نسخة من هذا المنشور على YouTube:
نظرة عامة
غالبًا ما يتم عرض عناصر على المستخدمين، وفي بعض الأحيان الكثير من العناصر، وفي هذه الحالات، قد يكون من المفيد توفير طريقة لتقليل القائمة من أجل تجنُّب فرط الخيارات. تستكشف مشاركة المدونة هذه واجهة مستخدم الفلترة كطريقة لتقليل الخيارات. ويتم ذلك من خلال عرض سمات المنتجات التي يمكن للمستخدمين اختيارها أو إلغاء اختيارها، ما يقلّل من عدد النتائج وبالتالي يقلّل من الشعور بالإرهاق بسبب كثرة الخيارات.
التفاعلات
الهدف هو إتاحة التنقّل السريع بين خيارات الفلتر لجميع المستخدمين وأنواع الإدخال المختلفة. وسيتم توفير ذلك من خلال زوج من المكوّنات المتجاوبة والقابلة للتكيّف. شريط جانبي تقليدي يتضمّن مربّعات اختيار على أجهزة الكمبيوتر المكتبي ولوحات المفاتيح وقارئات الشاشة، و<select
multiple>
لمستخدمي الأجهزة التي تعمل باللمس.
يوفّر هذا القرار باستخدام ميزة الاختيار المتعدد المضمّنة للأجهزة التي تعمل باللمس، وليس لأجهزة الكمبيوتر، الوقت والجهد، ولكنّني أعتقد أنّه يقدّم تجارب مناسبة مع عبء أقل في التعليمات البرمجية مقارنةً بإنشاء تجربة متجاوبة كاملة في مكوّن واحد.
لمس
يوفّر مكوّن اللمس مساحة ويساعد في دقة تفاعل المستخدم على الأجهزة الجوّالة. توفّر هذه الميزة مساحة من خلال تصغير شريط جانبي كامل من مربّعات الاختيار إلى تجربة لمس <select>
مدمجة. تساعد هذه الميزة في إدخال البيانات بدقة من خلال عرض تجربة تراكب كبيرة تعمل باللمس يوفّرها النظام.
لوحة المفاتيح وجهاز التحكّم في الألعاب
في ما يلي توضيح لكيفية استخدام <select multiple>
من لوحة المفاتيح.
لا يمكن تصميم أداة الاختيار المتعدد المضمّنة هذه، وهي متاحة فقط بتنسيق مضغوط لا يناسب عرض الكثير من الخيارات. ألا تلاحظ أنّك لا تستطيع رؤية مجموعة الخيارات الكاملة في هذا المربع الصغير؟ مع أنّه يمكنك تغيير حجمها، إلا أنّها لا تزال أقل فائدة من شريط جانبي يتضمّن مربّعات اختيار.
Markup
سيتم تضمين كلا المكوّنين في عنصر <form>
نفسه. سيتم رصد نتائج هذا النموذج، سواء كانت مربّعات اختيار أو خيارات متعدّدة، واستخدامها لفلترة الشبكة، ولكن يمكن أيضًا إرسالها إلى خادم.
<form>
</form>
مكوّن مربّعات الاختيار
يجب تضمين مجموعات مربّعات الاختيار في عنصر
<fieldset>
وتحديد
<legend>
لها.
عندما يتم تنظيم HTML بهذه الطريقة، ستفهم قارئات الشاشة وFormData العلاقة بين العناصر تلقائيًا.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
بعد إعداد التجميع، أضِف <label>
و<input type="checkbox">
لكل فلتر. لقد اخترت تضمينها في <div>
حتى تتمكّن السمة gap
في CSS من توزيعها بالتساوي والحفاظ على المحاذاة عندما تتعدّد أسطر التصنيفات.
<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
طريقة استخدام الميزة. يبدأ الدمج باستخدام HTML والسمة role="status"
.
<div role="status" class="sr-only" id="applied-filters"></div>
سيقرأ هذا العنصر بصوت عالٍ التغييرات التي تم إجراؤها على المحتوى. يمكننا تعديل المحتوى باستخدام عدادات CSS عندما يتفاعل المستخدمون مع مربّعات الاختيار. لإجراء ذلك، علينا أولاً إنشاء عدّاد باسم على عنصر رئيسي من عناصر الإدخال وعنصر الحالة.
aside {
counter-reset: filters;
}
سيكون العدد تلقائيًا 0
، وهو أمر رائع، لأنّه لا يوجد :checked
تلقائيًا في هذا التصميم.
بعد ذلك، لزيادة قيمة العداد الذي أنشأناه حديثًا، سنستهدف العناصر الفرعية من العنصر
<aside>
التي تكون :checked
. عندما يغيّر المستخدم حالة المدخلات، سيتم احتساب عدد مرات ظهور filters
.
aside :checked {
counter-increment: filters;
}
أصبح CSS الآن على دراية بالإجمالي العام لواجهة مستخدم مربّع الاختيار، وعنصر دور الحالة فارغ وينتظر القيم. بما أنّ CSS يحتفظ بالعدد في الذاكرة، تتيح الدالة
counter()
الوصول إلى القيمة من محتوى العنصر الزائف:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
سيُعلن الآن رمز HTML الخاص بعنصر دور الحالة عن "فلترَين " لقارئ الشاشة. هذه بداية جيدة، ولكن يمكننا تقديم تجربة أفضل، مثل مشاركة عدد النتائج التي تم تعديلها باستخدام الفلاتر. سننفّذ هذه العملية باستخدام JavaScript، لأنّها تتجاوز إمكانات العدادات.
الحماس بشأن الاستعداد للولادة
كانت خوارزمية العدادات رائعة مع 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
لأنّه من الشائع
توصيل ماوس أو جهاز إدخال آخر عالي الدقة.
مجموعات الحقول
يتميّز النمط والتنسيق التلقائيان <fieldset>
الذي يتضمّن <legend>
بما يلي:
في العادة، أستخدم الخاصية gap
لضبط المسافة بين العناصر الثانوية، ولكن بسبب طريقة تحديد موضع <legend>
الفريدة، يصعب إنشاء مجموعة من العناصر الثانوية ذات مسافات متساوية. بدلاً من gap
، يتم استخدام أداة اختيار العنصر الشقيق المجاور وmargin-block-start
.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
يؤدي ذلك إلى تخطّي تعديل مساحة العلامة <legend>
من خلال استهداف العلامات الثانوية <div>
فقط.
تصنيف الفلتر ومربّع الاختيار
بما أنّها علامة ثانوية مباشرة للعلامة <fieldset>
وضمن الحد الأقصى لعرض 30ch
الخاص بالنموذج، قد يتم التفاف نص التصنيف إذا كان طويلاً جدًا. تغليف النص أمر رائع، ولكن عدم محاذاة النص مع مربّع الاختيار ليس كذلك. يُعدّ Flexbox مثاليًا لهذا الغرض.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}

الشبكة المتحركة
يتم إنشاء الرسوم المتحركة للتنسيق باستخدام Isotope. إضافة فعّالة وقوية لفرز البيانات وتصفيتها بشكل تفاعلي.
JavaScript
بالإضافة إلى المساعدة في تنظيم شبكة تفاعلية متحركة أنيقة، يتم استخدام JavaScript لتعديل بعض التفاصيل البسيطة.
تسوية إدخال المستخدم
يتضمّن هذا التصميم نموذجًا واحدًا مع طريقتَين مختلفتَين لتقديم الإدخال، ولا يتم تسلسل الطريقتَين بالطريقة نفسها. باستخدام بعض رموز JavaScript، يمكننا تسوية البيانات.
لقد اخترت محاذاة بنية بيانات العنصر <select>
مع بنية مربّعات الاختيار المجمّعة. لإجراء ذلك، تتم إضافة أداة معالجة الحدث
input
إلى العنصر <select>
، وعند هذه النقطة، يتم ربط
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 نتيجة".
ستتوفّر الآن تجربة التكنولوجيا المساعدة الممتازة لجميع المستخدمين، بغض النظر عن طريقة تفاعلهم معها.
الخاتمة
بعد أن عرفت كيف فعلتُ ذلك، كيف ستفعل أنت ذلك؟ 🙂
لنستكشف الطرق المختلفة لإنشاء مواقع إلكترونية على الويب. يمكنك إنشاء عرض توضيحي، إرسال تغريدة إليّ تتضمّن رابطًا إليه، وسأضيفه إلى قسم "ريمكسات من المنتدى" أدناه.
ريمكسات من إنشاء المنتدى
ما مِن عناصر للاطّلاع عليها هنا حتى الآن.