Ringkasan dasar tentang cara membuat komponen multi-pilihan yang responsif, adaptif, dan mudah diakses untuk pengalaman pengguna pengurutan dan pemfilteran.
Dalam postingan ini, saya ingin membagikan pemikiran tentang cara membuat komponen multi-pilih. Coba demo.
Jika Anda lebih suka menonton video, berikut versi YouTube untuk postingan ini:
Ringkasan
Pengguna sering kali melihat item, terkadang banyak item, dan dalam kasus ini, sebaiknya berikan cara untuk mengurangi daftar guna mencegah kelebihan pilihan. Postingan blog ini mengeksplorasi UI pemfilteran sebagai cara untuk mengurangi pilihan. Hal ini dilakukan dengan menampilkan atribut item yang dapat dipilih atau dibatalkan pilihannya oleh pengguna, sehingga mengurangi hasil dan mengurangi kelebihan pilihan.
Interaksi
Tujuannya adalah memungkinkan traversal opsi filter yang cepat untuk semua pengguna dan
jenis input yang bervariasi. Hal ini akan dikirimkan dengan sepasang komponen
yang dapat disesuaikan dan responsif. Sidebar kotak centang tradisional untuk desktop, keyboard,
dan pembaca layar, serta <select
multiple>
untuk pengguna sentuh.
Keputusan untuk menggunakan multi-pilihan bawaan untuk sentuhan, dan bukan untuk desktop, ini menghemat pekerjaan dan menciptakan pekerjaan, tetapi saya yakin memberikan pengalaman yang sesuai dengan lebih sedikit hutang kode daripada membangun seluruh pengalaman responsif dalam satu komponen.
Sentuh
Komponen sentuh menghemat ruang dan membantu akurasi interaksi pengguna di
perangkat seluler. Hal ini menghemat ruang dengan menciutkan seluruh sidebar kotak centang ke dalam
pengalaman sentuh overlay bawaan <select>
. Hal ini membantu akurasi input dengan menampilkan
pengalaman overlay sentuh besar yang disediakan oleh sistem.
Keyboard dan gamepad
Di bawah ini adalah demonstrasi cara menggunakan <select multiple>
dari keyboard.
Multi-pilih bawaan ini tidak dapat diberi gaya dan hanya ditawarkan dalam tata letak ringkas yang tidak cocok untuk menampilkan banyak opsi. Lihat bagaimana Anda tidak bisa benar-benar melihat luasnya pilihan dalam kotak kecil itu? Meskipun dapat diubah ukurannya, ukurannya masih belum dapat digunakan seperti sidebar kotak centang.
Markup
Kedua komponen akan berada dalam elemen <form>
yang sama. Hasil
bentuk ini, baik kotak centang atau multi-pilihan, akan diamati dan digunakan untuk
memfilter petak, tetapi juga dapat dikirimkan ke server.
<form>
</form>
Komponen kotak centang
Grup kotak centang harus digabungkan dalam elemen
<fieldset>
dan diberi
<legend>
.
Ketika HTML disusun seperti ini, pembaca layar dan FormData akan otomatis memahami hubungan elemen.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Dengan pengelompokan yang sudah diterapkan, tambahkan <label>
dan <input type="checkbox">
untuk setiap filter. Saya memilih untuk menggabungkannya dalam <div>
sehingga properti gap
CSS
dapat mengatur spasi secara merata dan mempertahankan perataan saat label menjadi beberapa baris.
<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>
komponen
Fitur elemen <select>
yang jarang digunakan adalah
multiple
.
Jika atribut digunakan dengan elemen <select>
, pengguna diizinkan untuk
memilih banyak dari daftar. Ini seperti mengubah interaksi dari daftar pilihan
menjadi daftar kotak centang.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Untuk memberi label dan membuat grup di dalam <select>
, gunakan elemen
<optgroup>
dan beri atribut dan nilai label
. Elemen dan nilai
atribut ini mirip dengan elemen <fieldset>
dan <legend>
.
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
…
</optgroup>
</select>
</form>
Sekarang, tambahkan elemen
<option>
untuk filter.
<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>
Melacak input dengan penghitung untuk menginformasikan teknologi pendukung
Teknik status
role
digunakan dalam pengalaman pengguna ini, untuk melacak dan mempertahankan jumlah
filter untuk pembaca layar dan teknologi pendukung lainnya. Video YouTube menunjukkan fitur tersebut. Integrasi dimulai dengan HTML dan atribut
role="status"
.
<div role="status" class="sr-only" id="applied-filters"></div>
Elemen ini akan membacakan perubahan yang dibuat pada konten. Kita dapat memperbarui konten dengan penghitung CSS saat pengguna berinteraksi dengan kotak centang. Untuk melakukannya, pertama-tama kita harus membuat penghitung dengan nama pada elemen induk input dan elemen status.
aside {
counter-reset: filters;
}
Secara default, jumlahnya akan menjadi 0
, yang bagus, tidak ada yang :checked
secara
default dalam desain ini.
Selanjutnya, untuk menambahkan penghitung yang baru dibuat, kita akan menargetkan turunan elemen <aside>
yang merupakan :checked
. Saat pengguna mengubah status input,
penghitung filters
akan dijumlahkan.
aside :checked {
counter-increment: filters;
}
CSS sekarang mengetahui penghitungan umum UI kotak centang dan elemen peran status
kosong dan menunggu nilai. Karena CSS mempertahankan penghitungan dalam
memori, fungsi
counter()
memungkinkan akses ke nilai dari konten elemen
pseudo:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
HTML untuk elemen peran status kini akan mengumumkan "2 filter " ke pembaca layar. Ini adalah awal yang baik, tetapi kita bisa melakukannya dengan lebih baik, seperti membagikan jumlah hasil yang telah diperbarui filter. Kita akan melakukan pekerjaan ini dari JavaScript, karena di luar apa yang dapat dilakukan penghitung.
Peningkatan antusiasme
Algoritme penghitung terasa sangat cocok dengan CSS nesting-1, karena saya dapat menempatkan semua logika ke dalam satu blok. Terasa portabel dan terpusat untuk membaca dan memperbarui.
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
Tata letak
Bagian ini menjelaskan tata letak antara kedua komponen tersebut. Sebagian besar gaya tata letak digunakan untuk komponen kotak centang desktop.
Formulir
Untuk mengoptimalkan keterbacaan dan keterpindaian bagi pengguna, formulir diberi lebar maksimum
30 karakter, yang pada dasarnya menetapkan lebar baris optik untuk setiap
label filter. Formulir menggunakan tata letak petak dan properti gap
untuk mengatur jarak
fieldset.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
Elemen <select>
Daftar label dan kotak centang menghabiskan terlalu banyak ruang di perangkat seluler. Oleh karena itu, tata letak akan memeriksa apakah perangkat penunjuk utama pengguna untuk mengubah pengalaman sentuhan.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
Nilai coarse
menunjukkan bahwa pengguna tidak akan dapat berinteraksi dengan
layar dengan tingkat presisi tinggi menggunakan perangkat input utama mereka. Pada
perangkat seluler, nilai pointer sering kali adalah coarse
, karena interaksi utama
adalah sentuh. Di perangkat desktop, nilai pointer sering kali fine
karena mouse atau perangkat input presisi tinggi lainnya sering kali
terhubung.
Kumpulan kolom
Gaya visual dan tata letak default <fieldset>
dengan <legend>
bersifat unik:
Biasanya, untuk memberi spasi pada elemen turunan, saya akan menggunakan properti gap
, tetapi posisi unik
<legend>
mempersulit pembuatan kumpulan turunan
yang berjarak sama. Sebagai ganti gap
, pemilih saudara
terdekat dan
margin-block-start
digunakan.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Tindakan ini akan melewati <legend>
agar ruangnya tidak disesuaikan dengan hanya menargetkan
turunan <div>
.
Label filter dan kotak centang
Sebagai turunan langsung dari <fieldset>
dan dalam lebar maksimum
30ch
formulir, teks label dapat digabungkan jika terlalu panjang. Kemas teks itu bagus, tetapi ketidaksejajaran
antara teks dan kotak centang bisa jadi tidak demikian. Flexbox sangat cocok untuk hal ini.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
Petak animasi
Animasi tata letak dilakukan oleh Isotope. Plugin yang berperforma tinggi dan andal untuk pengurutan dan pemfilteran interaktif.
JavaScript
Selain membantu mengatur petak interaktif animasi yang rapi, JavaScript digunakan untuk memoles beberapa kekurangan.
Menormalkan input pengguna
Desain ini memiliki satu formulir dengan dua cara berbeda untuk memberikan input, dan keduanya tidak melakukan serialisasi yang sama. Dengan beberapa JavaScript, kita dapat menormalisasikan data.
Saya memilih untuk menyelaraskan struktur data elemen <select>
dengan struktur kotak centang
yang dikelompokkan. Untuk melakukannya, pemroses peristiwa
input
ditambahkan ke elemen <select>
, pada saat itu
selectedOptions
dipetakan.
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
}, [])
})
Sekarang Anda dapat mengirimkan formulir, atau dalam kasus demo ini, beri tahu Isotope apa yang akan difilter.
Menyelesaikan elemen peran status
Elemen ini hanya menghitung dan mengumumkan jumlah filter berdasarkan interaksi
kotak centang, tetapi saya merasa sebaiknya membagikan jumlah
hasil tambahan dan memastikan pilihan elemen <select>
juga dihitung.
Pilihan elemen <select>
tercermin dalam counter()
Di bagian normalisasi data, pemroses sudah dibuat pada input. Di akhir fungsi ini, jumlah filter yang dipilih dan jumlah hasil untuk filter tersebut diketahui. Nilai dapat diteruskan ke elemen peran status seperti ini.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Hasil ditampilkan dalam elemen role="status"
:checked
menyediakan cara bawaan untuk meneruskan jumlah filter yang dipilih ke elemen peran status, tetapi tidak memiliki visibilitas ke jumlah hasil yang difilter.
JavaScript dapat memantau interaksi dengan kotak centang dan setelah memfilter grid, menambahkan textContent
seperti yang dilakukan elemen <select>
.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
Secara keseluruhan, pekerjaan ini menyelesaikan pengumuman "2 filter memberikan 25 hasil".
Sekarang, pengalaman teknologi pendukung kami yang sangat baik akan diberikan kepada semua pengguna, apa pun cara mereka berinteraksi dengannya.
Kesimpulan
Setelah Anda tahu cara saya melakukannya, bagaimana Anda melakukannya‽ 🙂
Mari kita diversifikasi pendekatan dan pelajari semua cara untuk mem-build di web. Buat demo, tweet link-nya, dan saya akan menambahkannya ke bagian remix komunitas di bawah.
Remix komunitas
Belum ada apa-apa di sini.