סקירה כללית בסיסית של תהליך היצירה של רכיב רספונסיבי, נגיש ונגיש, שמאפשר מיון וסינון של חוויית המשתמש.
בפוסט הזה אני רוצה לשתף איתכם חשיבה על דרך לבניית רכיב לבחירה מרובה. כדאי לנסות את demo.
אם אתם מעדיפים סרטון, הנה גרסה של 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>
כך שהנכס של שירות ה-CSS 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
מדגים את התכונה. השילוב מתחיל ב-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 של רכיב תפקיד הסטטוס יכריז עכשיו '2 מסננים' למסך בקורא. זוהי התחלה טובה, אבל נוכל לעשות זאת, למשל, לשתף תוצאות שהמסננים עדכנו. נעשה את העבודה הזו מ-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
ה-event listener יתווסף לרכיב <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`
})
בסך הכול, העבודה הזו משלימה את ההודעה "2 מסננים שמספקים 25 תוצאות".
מעכשיו, חוויית השימוש המעולה שלנו בטכנולוגיה מסייעת תועבר לכל המשתמשים, בכל דרך שבה הם יוצרים אינטראקציה עם התוכן הזה.
סיכום
עכשיו, אחרי שהסברתי איך עשיתי את זה, איך היית? 🙂
בואו לגוון את הגישות שלנו ונלמד את כל הדרכים לבניית אתרים באינטרנט. אפשר ליצור הדגמה, לשלוח לי קישורים של שלחו לי ציוץ ואני אוסיף אותם לקטע 'רמיקסים' של הקהילה שבהמשך.
רמיקסים קהילתיים
אין כאן שום דבר עדיין לראות!