Ringkasan dasar tentang cara membangun komponen multi-pilihan yang responsif, adaptif, dan mudah diakses untuk mengurutkan dan memfilter pengalaman pengguna.
Dalam postingan ini, saya ingin berbagi pemikiran tentang cara membangun komponen multi-pilihan. Coba demonya.
Jika Anda lebih suka video, berikut versi YouTube postingan ini:
Ringkasan
Pengguna sering diberi item, terkadang banyak item, dan dalam hal ini, sebaiknya berikan cara untuk mengurangi daftar guna mencegah pilihan berlebihan. Postingan blog ini mempelajari pemfilteran UI sebagai cara untuk mengurangi pilihan. Caranya adalah dengan menampilkan atribut item yang dapat dipilih atau dibatalkan pilihan pengguna, sehingga mengurangi hasil sehingga mengurangi pilihan yang berlebihan.
Interaksi
Tujuannya adalah memungkinkan traversal cepat opsi filter untuk semua pengguna dan berbagai jenis input mereka. Ini akan dikirimkan dengan pasangan komponen yang
dapat disesuaikan dan responsif. Sidebar tradisional yang berisi kotak centang untuk desktop, keyboard
dan pembaca layar, serta <select
multiple>
untuk pengguna sentuh.
Keputusan untuk menggunakan multiselect bawaan untuk sentuhan, dan bukan untuk desktop, menghemat pekerjaan dan menciptakan pekerjaan, tetapi saya yakin memberikan pengalaman yang sesuai dengan lebih sedikit kode utang dibandingkan membangun seluruh pengalaman responsif dalam satu komponen.
Sentuh
Komponen sentuh menghemat ruang dan membantu akurasi interaksi pengguna di
perangkat seluler. Fitur ini menghemat ruang dengan menciutkan seluruh sidebar kotak centang menjadi
pengalaman sentuh overlay bawaan <select>
. Hal ini membantu akurasi input dengan menampilkan
pengalaman overlay sentuh besar yang disediakan oleh sistem.
Keyboard dan gamepad
Berikut adalah demonstrasi cara menggunakan <select multiple>
dari keyboard.
Multi-pilihan 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 Anda dapat mengubah ukurannya, itu masih tidak dapat digunakan layaknya {i>sidebar<i} dari kotak centang.
Markup
Kedua komponen akan dimuat dalam elemen <form>
yang sama. Hasil
formulir ini, baik kotak centang atau multi-pilihan, akan diamati dan digunakan untuk
memfilter petak, tetapi juga dapat dikirim ke server.
<form>
</form>
Komponen kotak centang
Grup kotak centang harus digabungkan dalam elemen
<fieldset>
dan diberi
<legend>
.
Jika HTML disusun dengan cara ini, pembaca layar dan FormData akan otomatis memahami hubungan elemen.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Setelah pengelompokan tersedia, tambahkan <label>
dan <input type="checkbox">
untuk
setiap filter. Saya memilih untuk menggabungkan milik saya dalam <div>
sehingga properti gap
CSS
dapat mengaturnya secara merata dan mempertahankan keselarasan saat label menjadi multigaris.
<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 yang jarang digunakan dari elemen <select>
adalah
multiple
.
Jika atribut digunakan dengan elemen <select>
, pengguna diizinkan untuk
memilih banyak dari daftar. Ini seperti mengubah interaksi dari
daftar radio ke 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 berikan atribut serta nilai label
. Elemen dan nilai atribut ini
serupa 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 peran
status
digunakan dalam pengalaman pengguna ini untuk melacak dan mempertahankan penghitungan
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 dari elemen input dan 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>
yaitu :checked
. Saat pengguna mengubah status input,
penghitung filters
akan menghitung.
aside :checked {
counter-increment: filters;
}
CSS kini mengetahui perhitungan umum UI kotak centang dan elemen peran status
kosong dan menunggu nilai. Karena CSS mempertahankan penghitungan dalam
memori, fungsi
counter()
memungkinkan akses 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 dapat melakukan yang lebih baik, seperti membagikan jumlah hasil yang telah diperbarui filter. Kita akan melakukan pekerjaan ini dari JavaScript, karena di luar apa yang bisa dilakukan penghitung.
Meningkatkan antusiasme
Algoritma penghitung terasa sangat baik dengan CSS nesting-1, karena saya dapat menempatkan semua logika ke dalam satu blok. Terasa portabel dan terpusat untuk membaca dan mengupdate.
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. Sebagian besar gaya tata letak ditujukan untuk komponen kotak centang desktop.
Formulir
Untuk mengoptimalkan keterbacaan dan pemindaian bagi pengguna, formulir diberi lebar
maksimum 30 karakter, yang pada dasarnya menyetel lebar garis optik untuk setiap
label filter. Formulir ini 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 pada perangkat seluler. Oleh karena itu, tata letak akan memeriksa untuk melihat perangkat penunjuk utama pengguna guna mengubah pengalaman sentuhan.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
Nilai coarse
menunjukkan bahwa pengguna tidak akan dapat berinteraksi dengan
layar secara presisi dengan perangkat input utamanya. Pada
perangkat seluler, nilai pointer sering kali adalah coarse
, karena interaksi utamanya
berupa sentuhan. Pada perangkat desktop, nilai pointer sering kali fine
karena umumnya
terhubung dengan mouse atau perangkat input presisi tinggi lainnya.
Fieldset
Gaya visual dan tata letak default <fieldset>
dengan <legend>
bersifat unik:
Biasanya, untuk memberikan spasi pada elemen turunan, saya akan menggunakan properti gap
, tetapi posisi
unik <legend>
menyulitkan pembuatan kumpulan turunan
yang berjarak sama. Sebagai ganti gap
, pemilih
seinduk yang berdekatan dan
margin-block-start
digunakan.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Tindakan ini akan mencegah <legend>
menyesuaikan ruangnya 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. Membungkus teks memang bagus, tetapi
ketidaksejajaran antara teks dan kotak centang tidak baik. Flexbox ideal untuk ini.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
Petak animasi
Animasi tata letak dilakukan oleh Isotope. Plugin yang berperforma dan canggih untuk pengurutan dan filter interaktif.
JavaScript
Selain membantu mengorkestrasi petak interaktif animasi yang rapi, JavaScript digunakan untuk memperbaiki beberapa masalah.
Menormalkan input pengguna
Desain ini memiliki satu bentuk dengan dua cara berbeda untuk memberikan input, dan tidak melakukan serialisasi yang sama. Namun, dengan beberapa JavaScript, kita dapat menormalisasi data.
Saya memilih untuk menyelaraskan struktur data elemen <select>
dengan struktur kotak
centang yang dikelompokkan. Untuk melakukannya, pemroses peristiwa input
ditambahkan ke elemen <select>
, yang pada saat itu selectedOptions
akan 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 aman untuk mengirimkan formulir, atau dalam kasus demo ini, beri tahu Isotop tentang apa yang harus difilter.
Menyelesaikan elemen peran status
Elemen ini hanya menghitung dan mengumumkan jumlah filter berdasarkan interaksi
kotak centang, tetapi saya merasa sebaiknya membagikan jumlah
hasil 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 ditunjukkan 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
petak, tambahkan 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 melengkapi pengumuman "2 filter yang memberikan 25 hasil".
Kini pengalaman teknologi pendukung kami yang sangat baik akan dapat dimanfaatkan oleh semua pengguna, dengan cara apa pun mereka berinteraksi dengannya.
Kesimpulan
Setelah Anda tahu cara saya melakukannya, bagaimana Anda‽ 🙂
Mari lakukan diversifikasi pendekatan dan pelajari semua cara untuk membangun di web. Buat demo, link tweet me, dan saya akan menambahkannya ke bagian remix komunitas di bawah.
Remix komunitas
Belum ada apa-apa di sini.