Kullanıcı deneyimlerini sıralamak ve filtrelemek için duyarlı, uyarlanabilir, erişilebilir, çoklu seçim bileşeni oluşturmaya temel bir genel bakış.
Bu yayında, çoklu seçim bileşeni oluşturmanın bir yolu üzerine düşünmek istiyorum. Demoyu deneyin.
Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:
Genel bakış
Kullanıcılara sıklıkla öğeler (bazen çok çok sayıda öğe) sunulur. Bu durumlarda, çok fazla seçenek olmasını önlemek için listeyi küçültecek bir yöntem sunmak iyi bir fikir olabilir. Bu blog yayınında, seçim sayısını azaltmanın bir yolu olarak filtreleme kullanıcı arayüzü ele alınmaktadır. Bunu, kullanıcıların seçebileceği veya seçimini kaldırabileceği öğe özellikleri sunarak, sonuçları azaltarak ve böylece seçim yükünü azaltarak yapar.
Etkileşimler
Amaç, tüm kullanıcılar ve bunların değişen giriş türleri için filtre seçenekleri arasında hızlı geçişe olanak tanımaktır. Bu, uyarlanabilir ve duyarlı bir bileşen çiftiyle teslim edilecektir. Masaüstü, klavye ve ekran okuyucular için onay kutularından oluşan geleneksel bir
kenar çubuğu; dokunmatik kullanıcılar için bir
<select
multiple>
.
Masaüstü için değil, dokunma için yerleşik çoklu seçim özelliğini kullanma kararı iş tasarrufu sağlıyor ve iş yaratıyor. Ancak tüm duyarlı deneyimi tek bir bileşende oluşturmaktan daha az kod borcuyla uygun deneyimler sağladığına inanıyorum.
Dokunma
Dokunma bileşeni yerden tasarruf sağlar ve mobil cihazlarda kullanıcı etkileşimi doğruluğunun sağlanmasına yardımcı olur. Onay kutuları içeren kenar çubuğunu tümüyle <select>
yerleşik bir yer paylaşımlı dokunma deneyimine daraltarak yerden tasarruf sağlar. Sistemin sağladığı geniş dokunmatik yer paylaşımı deneyimini göstererek giriş doğruluğuna yardımcı olur.
Klavye ve oyun kumandası
Aşağıda, klavyeden <select multiple>
öğesinin nasıl kullanılacağına ilişkin bir tanıtım yer almaktadır.
Bu yerleşik çoklu seçim özelliği, stil özellikleri ayarlanamaz ve yalnızca çok sayıda seçenek sunulmasına uygun olmayan kompakt bir düzende sunulur. O küçücük kutuda o kadar fazla seçeneği nasıl göremediğinizi anladınız mı? Boyutunu değiştirebilseniz de onay kutularından oluşan bir kenar çubuğu kadar kullanılabilir değildir.
Markup
Her iki bileşen de aynı <form>
öğesinde yer alır. Bu formun sonuçları, ister onay kutuları ister çoklu seçim olsun, gözlemlenir ve tabloyu filtrelemek için kullanılır, ancak bir sunucuya da gönderilebilir.
<form>
</form>
Onay kutuları bileşeni
Onay kutusu grupları bir <fieldset>
öğesi içine yerleştirilmeli ve bir <legend>
verilmelidir.
HTML bu şekilde yapılandırıldığında, ekran okuyucular ve FormData öğelerin ilişkisini otomatik olarak anlar.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Grup oluşturulduktan sonra, her filtre için bir <label>
ve <input type="checkbox">
ekleyin. Benimkini bir <div>
içine sarmayı seçtim. Böylece etiketler çok satırlı olduğunda CSS gap
özelliği bunları eşit şekilde dağıtabilir ve hizalamayı koruyabilir.
<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>
bileşeni
<select>
öğesinin nadir kullanılan bir özelliği de multiple
şeklindedir.
Özellik bir <select>
öğesiyle kullanıldığında kullanıcının listeden birçok seçim yapmasına izin verilir. Etkileşimi bir radyo listesinden onay kutusu
listesine dönüştürmeye benzer.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Bir <select>
içinde etiketlemek ve grup oluşturmak için <optgroup>
öğesini kullanarak label
özelliği ve değeri verin. Bu öğe ve özellik değeri, <fieldset>
ve <legend>
öğelerine benzer.
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
…
</optgroup>
</select>
</form>
Şimdi filtre için <option>
öğelerini ekleyin.
<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>
Yardımcı teknolojiler için bilgi sağlayan sayaçlarla girişi izleme
Bu kullanıcı deneyiminde durum rolü tekniği, ekran okuyucuları ve diğer yardımcı teknolojiler için filtrelerin kaydını izlemek ve tutmak için kullanılır. Bu özellik YouTube videosunda
açıklanıyor. Entegrasyon, HTML ve role="status"
özelliğiyle başlar.
<div role="status" class="sr-only" id="applied-filters"></div>
Bu öğe, içerikte yapılan değişiklikleri sesli okur. Kullanıcılar onay kutularıyla etkileşimde bulunurken içerikleri CSS sayaçları ile güncelleyebiliriz. Bunu yapmak için önce girişlerin ve durum öğesinin üst öğesinde adı olan bir sayaç oluşturmamız gerekir.
aside {
counter-reset: filters;
}
Varsayılan olarak sayı 0
olur. Bu harikadır. Bu tasarımda varsayılan olarak :checked
değeri yoktur.
Daha sonra, yeni oluşturulan sayacımızı artırmak için <aside>
öğesinin :checked
alt öğelerini hedefleyeceğiz. Kullanıcı, girişlerin durumunu değiştirdikçe filters
sayacı buna göre ayarlanır.
aside :checked {
counter-increment: filters;
}
CSS artık onay kutusu kullanıcı arayüzünün genel hesabını biliyor ve durum rolü öğesi boş ve değerleri bekliyor. CSS, kaydı bellekte tuttuğundan counter()
işlevi, sözde öğe içeriklerindeki değere erişime izin verir:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Durum rolü öğesinin HTML'si artık bir ekran okuyucuya "2 filtre" mesajını duyurdu. Bu iyi bir başlangıç, ama biz daha iyisini yapabiliriz. Örneğin, filtrelerin güncellediği sonuçların kaydını paylaşabiliriz. Bu işi JavaScript'ten yapacağız, çünkü sayaçların yapabildiklerinin dışında.
Yuva heyecanı
Tüm mantığı tek bir bloka yerleştirebildiğim için sayaç algoritması, CSS Nesting-1 ile çok iyi bir fikirdi. Taşınabilir ve merkezi bir şekilde okuma ve güncelleme için kullanılabilir.
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
Düzenler
Bu bölümde, iki bileşen arasındaki düzenler açıklanmaktadır. Düzen stillerinin çoğu masaüstü onay kutusu bileşenine yöneliktir.
Form
Kullanıcıların okunabilirliğini ve taranabilirliğini optimize etmek için forma maksimum 30 karakter genişliği verilir. Bu genişlik temelde her filtre etiketi için bir optik çizgi genişliği ayarlanır. Form, alan kümeleri arasında boşluk bırakmak için ızgara düzenini ve gap
özelliğini kullanır.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
<select>
öğesi
Hem etiket listesi hem de onay kutuları mobil cihazlarda çok fazla yer kaplar. Bu nedenle düzen, dokunma deneyimini değiştirmek için kullanıcının birincil işaretleme cihazını kontrol eder.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
coarse
değeri, kullanıcının birincil giriş cihazını kullanarak ekranla yüksek hassasiyetle etkileşimde bulunamayacağını belirtir. Mobil cihazlarda, birincil etkileşim dokunma olduğundan işaretçi değeri genellikle coarse
'dir. İşaretçi değeri, masaüstü cihazlarda fare veya başka bir yüksek hassasiyete sahip giriş cihazının bağlı olması yaygın olarak kullanıldığı için genellikle fine
'dir.
Alan kümeleri
<legend>
içeren <fieldset>
öğesinin varsayılan stili ve düzeni benzersizdir:
Normalde, alt öğelerimi boşluk bırakmak için gap
özelliğini kullanırım ancak <legend>
öğesinin benzersiz konumlandırılması, eşit aralıklı bir alt öğe grubu oluşturmayı zorlaştırır. gap
yerine, bitişik olan eşdüzey seçici ve margin-block-start
kullanılır.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Bu işlem, <legend>
alanının yalnızca <div>
alt öğelerini hedefleyerek düzenlenmesini engeller.
Filtre etiketi ve onay kutusu
<fieldset>
öğesinin doğrudan alt öğesi olarak ve formun 30ch
etiketinin maksimum genişliği dahilinde, etiket metni çok uzunsa kayabilir. Metni kaydırmak harika bir şey, ancak
metin ile onay kutusu arasındaki yanlış hizalama değil. Flexbox, bunun için idealdir.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
![Çok satırlı sarmalama senaryosunda onay işaretinin metnin ilk satırıyla nasıl hizalandığını gösteren ekran görüntüsü.](https://web.dev/static/articles/building/a-multi-select-component/image/screenshot-showing-the-c-b135285ef7d8a.png?authuser=6&hl=tr)
Animasyonlu ızgara
Düzen animasyonu, Isotope tarafından yapılır. Etkileşimli sıralama ve filtreleme için yüksek performanslı, güçlü bir eklenti.
JavaScript
JavaScript, düzgün animasyonlu, etkileşimli bir ızgaranın düzenlenmesine yardımcı olmanın yanı sıra birkaç pürüzlü kenarı parlatmak için de kullanılır.
Kullanıcı girişini normalleştirme
Bu tasarımda, giriş sağlamak için iki farklı yol içeren tek bir biçim vardır ve aynı şekilde serileştirme yapılmaz. Yine de bazı JavaScript'lerle verileri normalleştirebiliriz.
<select>
öğesinin veri yapısını gruplandırılmış onay kutuları yapısıyla hizalamayı seçtim. Bunu yapmak için <select>
öğesine bir input
etkinlik işleyici eklenir ve bu noktada selectedOptions
eşlenir.
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
}, [])
})
Artık formu güvenle gönderebilir ya da bu demoda Isotope'a neyi filtreleyeceğini öğretebilirsiniz.
Durum rolü öğesini tamamlama
Bu öğe yalnızca onay kutusu etkileşimine dayalı filtre sayısını hesaplıyor ve duyuruyor, ancak sonuçların sayısını ek olarak paylaşmanın ve <select>
öğe seçeneklerinin de sayılmasını sağlamanın iyi bir fikir olduğunu düşündüm.
<select>
öğe seçimi counter()
bölümüne yansıtıldı
Veri normalleştirme bölümünde, girişte bir işleyici zaten oluşturuldu. Bu işlevin sonunda, seçilen filtrelerin sayısı ve bu filtreler için sonuçların sayısı bilinmektedir. Değerler, durum rolü öğesine bu şekilde geçirilebilir.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Sonuçlar role="status"
öğesine yansıtılır
:checked
, seçilen filtre sayısını durum rolü öğesine geçirmek için yerleşik bir yol sağlar, ancak filtrelenmiş sonuç sayısını göremez.
JavaScript, onay kutularıyla etkileşimi izleyebilir ve ızgarayı filtreledikten sonra <select>
öğesinin yaptığı gibi textContent
öğesini ekleyin.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
Bu çalışma tümüyle "2 filtre, 25 sonuç verir" duyurusunu tamamlar.
Artık mükemmel yardımcı teknoloji deneyimimiz, kullanıcılarla ne şekilde etkileşimde bulunurlar olsunlar kullanıcılara sunulacak.
Sonuç
Nasıl yaptığımı artık bildiğine göre siz de nasıl yapardınız? 🙂
Yaklaşımlarımızı çeşitlendirelim ve web'de geliştirme yapmanın tüm yollarını öğrenelim. Bir demo oluşturun, bana tweet atın bağlantıları, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.
Topluluk remiksleri
Henüz burada görülecek bir şey yok.