ساخت یک جزء چند انتخابی

یک نمای کلی از نحوه ایجاد یک مؤلفه پاسخگو، تطبیقی ​​و در دسترس، چند انتخابی برای مرتب کردن و فیلتر کردن تجربیات کاربر.

در این پست می‌خواهم تفکری در مورد روشی برای ساختن یک جزء چند انتخابی به اشتراک بگذارم. نسخه ی نمایشی را امتحان کنید.

نسخه ی نمایشی

اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:

بررسی اجمالی

اغلب موارد، گاهی اوقات موارد زیادی به کاربران ارائه می شود، و در این موارد ارائه راهی برای کاهش لیست برای جلوگیری از اضافه بار انتخاب می تواند ایده خوبی باشد. این پست وبلاگ فیلتر کردن UI را به عنوان راهی برای کاهش انتخاب ها بررسی می کند. این کار را با ارائه ویژگی‌های آیتمی انجام می‌دهد که کاربران می‌توانند آن‌ها را انتخاب یا از حالت انتخاب خارج کنند، نتایج را کاهش می‌دهد و در نتیجه اضافه بار انتخاب را کاهش می‌دهد.

فعل و انفعالات

هدف فعال کردن پیمایش سریع گزینه‌های فیلتر برای همه کاربران و انواع ورودی آنهاست. این با یک جفت مؤلفه سازگار و پاسخگو ارائه می شود. یک نوار کناری سنتی از چک باکس ها برای دسکتاپ، صفحه کلید و خوانندگان صفحه، و یک <select multiple> برای کاربران لمسی.

مقایسه اسکرین شات روشن و تاریک دسکتاپ را با نوار کناری چک باکس در مقایسه با iOS و Android موبایل با یک عنصر چند انتخابی.

این تصمیم برای استفاده از چند انتخاب داخلی برای لمس، و نه برای دسکتاپ، باعث صرفه‌جویی در کار و ایجاد کار می‌شود، اما من معتقدم تجربیات مناسب با بدهی کد کمتری نسبت به ساخت کل تجربه پاسخ‌گو در یک مؤلفه ارائه می‌کند.

دست زدن به

مولفه لمسی باعث صرفه جویی در فضا می شود و به دقت تعامل کاربر در تلفن همراه کمک می کند. با جمع کردن کل یک نوار کناری از چک باکس ها در یک تجربه لمسی داخلی روی همپوشانی <select> در فضا صرفه جویی می کند. با نمایش یک تجربه پوشش لمسی بزرگ ارائه شده توسط سیستم، به دقت ورودی کمک می کند.

پیش‌نمایش تصویری از عنصر چند انتخابی در Chrome در Android، iPhone و iPad. آی‌پد و آیفون دارای گزینه چند انتخابی باز هستند و هر کدام یک تجربه منحصربه‌فرد بهینه‌سازی شده برای اندازه صفحه نمایش دارند.

کیبورد و گیم پد

در زیر نمایشی از نحوه استفاده از <select multiple> از صفحه کلید است.

این مولتی انتخاب داخلی را نمی توان استایل کرد و فقط در یک طرح جمع و جور ارائه می شود که برای ارائه گزینه های زیاد مناسب نیست. ببینید چگونه واقعا نمی توانید وسعت گزینه ها را در آن جعبه کوچک ببینید؟ در حالی که می توانید اندازه آن را تغییر دهید، هنوز به اندازه نوار کناری چک باکس ها قابل استفاده نیست.

نشانه گذاری

هر دو مؤلفه در یک عنصر <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>

تصویری از رندر دسکتاپ یک عنصر چند انتخابی.

ردیابی ورودی با شمارنده برای اطلاع رسانی فناوری کمکی

تکنیک نقش وضعیت در این تجربه کاربری برای ردیابی و حفظ فهرست فیلترها برای صفحه‌خوان‌ها و سایر فناوری‌های کمکی استفاده می‌شود. ویدیوی یوتیوب این ویژگی را نشان می دهد. ادغام با 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 فیلتر" را به یک صفحه خوان اعلام می کند. این شروع خوبی است، اما ما می‌توانیم بهتر عمل کنیم، مانند به اشتراک گذاشتن نتایجی که فیلترها به‌روزرسانی کرده‌اند. ما این کار را از جاوا اسکریپت انجام خواهیم داد، زیرا خارج از آن چیزی است که شمارنده ها می توانند انجام دهند.

تصویری از صفحه‌خوان 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 است، زیرا اتصال ماوس یا سایر دستگاه های ورودی با دقت بالا معمول است.

مجموعه های فیلد

استایل و چیدمان پیش فرض یک <fieldset> با <legend> منحصر به فرد است:

تصویری از سبک های پیش فرض برای مجموعه فیلدها و افسانه ها.

به طور معمول، برای ایجاد فاصله بین عناصر فرزند خود از ویژگی gap استفاده می‌کنم، اما موقعیت منحصربه‌فرد <legend> ایجاد مجموعه‌ای از کودکان با فاصله یکسان را دشوار می‌کند. به جای gap ، از انتخابگر خواهر و برادر مجاور و margin-block-start استفاده می شود.

fieldset {
  padding: 2ch;

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

با هدف قرار دادن فقط کودکان <div> <legend> از تنظیم فضای آن صرفنظر می کند.

اسکرین شات فاصله حاشیه بین ورودی ها را نشان می دهد اما افسانه را نشان نمی دهد.

برچسب فیلتر و چک باکس

به عنوان فرزند مستقیم یک <fieldset> و در حداکثر عرض 30ch فرم، ممکن است متن برچسب در صورت طولانی بودن بسته شود. بسته بندی متن عالی است، اما عدم تراز بین متن و چک باکس اینطور نیست. Flexbox برای این کار ایده آل است.

fieldset > div {
  display: flex;
  gap: 2ch;
  align-items: baseline;
}
اسکرین شات نشان می دهد که چگونه علامت چک با خط اول متن در یک سناریوی بسته بندی چند خطی تراز می شود.
در این Codepen بیشتر بازی کنید

شبکه متحرک

انیمیشن طرح بندی توسط ایزوتوپ انجام شده است. یک پلاگین کارآمد و قدرتمند برای مرتب سازی و فیلتر تعاملی.

جاوا اسکریپت

جاوا اسکریپت علاوه بر کمک به تنظیم یک شبکه متحرک و تعاملی منظم، برای صیقل دادن چند لبه ناهموار استفاده می شود.

عادی کردن ورودی کاربر

این طرح دارای یک فرم با دو روش مختلف برای ارائه ورودی است و آنها به صورت سریالی یکسان نیستند. با وجود برخی از جاوا اسکریپت، می‌توانیم داده‌ها را عادی کنیم .

اسکرین شات کنسول جاوا اسکریپت DevTools که نتایج داده های هدف و نرمال شده را نشان می دهد.

من تراز کردن ساختار داده عنصر <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
  }, [])
})

اکنون می توانید فرم را ارسال کنید، یا در مورد این نسخه آزمایشی، به ایزوتوپ آموزش دهید که بر اساس چه چیزی فیلتر شود.

تکمیل عنصر نقش وضعیت

عنصر فقط شمارش و تعداد فیلترها را بر اساس تعامل چک باکس اعلام می کند، اما من فکر می کنم ایده خوبی است که علاوه بر این تعداد نتایج را به اشتراک بگذارم و اطمینان حاصل کنیم که گزینه های عنصر <select> نیز شمارش می شوند.

انتخاب عنصر <select> در counter() منعکس شده است

در بخش عادی سازی داده ها، یک شنونده قبلاً در ورودی ایجاد شده است. در پایان این تابع، تعداد فیلترهای انتخابی و تعداد نتایج آن فیلترها مشخص است. مقادیر را می توان به این شکل به عنصر نقش وضعیت منتقل کرد.

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

نتایج در عنصر role="status" منعکس شده است

:checked یک روش داخلی برای انتقال تعداد فیلترهای انتخابی به عنصر نقش وضعیت ارائه می دهد، اما برای تعداد فیلتر شده نتایج قابل مشاهده نیست. جاوا اسکریپت می تواند تعامل با چک باکس ها را تماشا کند و پس از فیلتر کردن شبکه، 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 نتیجه می دهد" را تکمیل می کند.

تصویری از صفحه‌خوان MacOS که نتایج را اعلام می‌کند.

اکنون تجربه عالی فناوری کمکی ما در اختیار همه کاربران قرار خواهد گرفت، هر چند که با آن تعامل داشته باشند.

نتیجه

حالا که می دانید من چگونه این کار را انجام دادم، چگونه این کار را انجام می دهید‽🙂

بیایید رویکردهایمان را متنوع کنیم و همه راه‌های ساخت در وب را بیاموزیم. یک نسخه نمایشی ایجاد کنید، پیوندها را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم!

ریمیکس های انجمن

هنوز چیزی برای دیدن اینجا وجود ندارد!