Sıralama ve filtreleme kullanıcı deneyimleri için duyarlı, uyarlanabilir ve erişilebilir bir çoklu seçim bileşeni oluşturma hakkında temel bilgiler.
Bu yayında, çoklu seçim bileşeni oluşturma yöntemleriyle ilgili düşüncelerimi paylaşmak istiyorum. Demoyu deneyin.
Video tercih ediyorsanız bu yayının YouTube versiyonunu aşağıda bulabilirsiniz:
Genel Bakış
Kullanıcılara genellikle öğeler, bazen de çok sayıda öğe sunulur. Bu durumlarda, seçenek bolluğunu önlemek için listeyi azaltmanın bir yolunu sunmak iyi bir fikir olabilir. Bu blog yayınında, seçenekleri azaltmanın bir yolu olarak filtreleme kullanıcı arayüzü ele alınmaktadır. Bu işlem, kullanıcıların seçebileceği veya seçimini kaldırabileceği öğe özelliklerini sunarak yapılır. Böylece sonuç sayısı ve dolayısıyla seçenek fazlalığı azaltılır.
Etkileşimler
Amaç, tüm kullanıcıların ve farklı giriş türlerinin filtre seçenekleri arasında hızlıca gezinmesini sağlamaktır. Bu, uyarlanabilir ve duyarlı bir bileşen çiftiyle birlikte sunulur. Masaüstü, klavye ve ekran okuyucular için onay kutularının bulunduğu geleneksel bir kenar çubuğu, dokunmatik kullanıcılar için ise <select
multiple>
.
Dokunma için yerleşik çoklu seçim özelliğini kullanma ve masaüstü için kullanmama kararı, iş yükünü azaltır ve artırır ancak tüm duyarlı deneyimi tek bir bileşende oluşturmaya kıyasla daha az kod borcuyla uygun deneyimler sunduğunu düşünüyorum.
Dokunma
Dokunma bileşeni, alandan tasarruf etmenizi sağlar ve mobil cihazlarda kullanıcı etkileşiminin doğruluğuna yardımcı olur. Tüm onay kutularının bulunduğu kenar çubuğunu <select>
yerleşik bir yer paylaşımı dokunma deneyimine daraltarak yer tasarrufu sağlar. Sistem tarafından sağlanan büyük bir dokunma katmanı deneyimi göstererek giriş doğruluğuna yardımcı olur.
Klavye ve oyun kumandası
Klavyeden <select multiple>
nasıl kullanılacağına dair bir gösterimi aşağıda bulabilirsiniz.
Bu yerleşik çoklu seçim özelliği stilize edilemez ve yalnızca çok sayıda seçeneğin sunulması için uygun olmayan kompakt bir düzende sunulur. O küçük kutuda seçeneklerin tamamını göremediğinizi fark ettiniz mi? Boyutunu değiştirebilirsiniz ancak yine de onay kutularının bulunduğu bir kenar çubuğu kadar kullanışlı değildir.
Brüt kar
Her iki bileşen de aynı <form>
öğesinde yer alır. Bu formun sonuçları (onay kutuları veya çoklu seçim) gözlemlenir ve ızgarayı filtrelemek için kullanılır ancak bir sunucuya da gönderilebilir.
<form>
</form>
Onay kutuları bileşeni
Onay kutusu grupları bir <fieldset>
öğesine sarılmalı ve <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>
Gruplandırma yapıldıktan sonra her filtre için <label>
ve <input type="checkbox">
ekleyin. CSS gap
özelliği, etiketler çok satırlı olduğunda aralarındaki boşluğu eşit şekilde dağıtıp hizalamayı koruyabilsin diye etiketlerimi <div>
içine almayı tercih ettim.
<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 nadiren kullanılan bir özelliği multiple
.
Özellik bir <select>
öğesiyle kullanıldığında kullanıcının listeden birden fazla seçenek belirlemesine izin verilir. Etkileşimi radyo listesinden onay kutusu listesine değiştirmeye benzer.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
<select>
içinde grupları etiketlemek ve oluşturmak için <optgroup>
öğesini kullanın ve bu öğeye 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ı teknolojilere bilgi vermek için sayaçlarla girişi izleme
Bu kullanıcı deneyiminde, ekran okuyucular ve diğer yardımcı teknolojiler için filtrelerin sayısını izlemek ve korumak amacıyla durum
rolü tekniği kullanılır. YouTube videosunda özellik gösteriliyor. Entegrasyon, HTML ve role="status"
özelliğiyle başlar.
<div role="status" class="sr-only" id="applied-filters"></div>
Bu öğe, içeriklerde yapılan değişiklikleri sesli okur. Kullanıcılar onay kutularıyla etkileşimde bulundukça CSS sayaçları ile içerikleri güncelleyebiliriz. Bunu yapmak için öncelikle girişlerin ve durum öğesinin üst öğesinde ad içeren bir sayaç oluşturmamız gerekir.
aside {
counter-reset: filters;
}
Varsayılan olarak sayı 0
olur. Bu harika bir durumdur. Bu tasarımda varsayılan olarak hiçbir şey :checked
değildir.
Ardından, yeni oluşturduğumuz sayacı artırmak için <aside>
öğesinin :checked
olan alt öğelerini hedefleyeceğiz. Kullanıcı girişlerin durumunu değiştirdikçe filters
sayacı artar.
aside :checked {
counter-increment: filters;
}
CSS artık onay kutusu kullanıcı arayüzünün genel sayısını biliyor ve durum rolü öğesi boş olup değerleri bekliyor. CSS, toplamı bellekte tuttuğundan counter()
işlevi, değeri sözde öğe içeriklerinden erişmeye olanak tanır:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Durum rolü öğesinin HTML'si artık ekran okuyucuya "2 filtre" olarak okunacak. Bu iyi bir başlangıç olsa da filtrelerin güncellediği sonuçların sayısını paylaşmak gibi daha iyi bir çözüm sunabiliriz. Sayaçların yapabileceklerinin dışında olduğundan bu işlemi JavaScript'ten yapacağız.
Yuva yapma heyecanı
Sayaç algoritması, tüm mantığı tek bir blokta toplayabildiğim için CSS nesting-1 ile harika çalıştı. Okuma ve güncelleme için taşınabilir ve merkezi bir deneyim sunar.
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. Çoğu düzen stili, masaüstü onay kutusu bileşeni içindir.
Form
Kullanıcılar için okunabilirliği ve taranabilirliği optimize etmek amacıyla forma maksimum 30 karakter genişlik verilir. Bu sayede, her filtre etiketi için optik bir satır genişliği belirlenir. Formda, alan kümeleri arasında boşluk bırakmak için ızgara düzeni ve gap
özelliği kullanılıyor.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
<select>
öğesi
Etiket listesi ve onay kutuları mobil cihazda çok fazla yer kaplıyor. 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ıyla ekrana yüksek hassasiyetle dokunamayacağını gösterir. Bir mobil cihazda, birincil etkileşim dokunma olduğu için işaretçi değeri genellikle coarse
olur. Masaüstü cihazlarda, fare veya başka bir yüksek hassasiyetli giriş cihazı bağlı olması yaygın olduğundan işaretçi değeri genellikle fine
olur.
Alan kümeleri
<legend>
içeren bir <fieldset>
öğesinin varsayılan stili ve düzeni benzersizdir:
Normalde alt öğelerimi aralandırmak için gap
özelliğini kullanırdım ancak <legend>
öğesinin benzersiz konumlandırması, eşit aralıklı bir alt öğe grubu oluşturmayı zorlaştırıyor. gap
yerine adjacent sibling
selector ve
margin-block-start
kullanılır.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Bu, yalnızca <div>
alt öğeleri hedeflenerek <legend>
öğesinin alanının ayarlanmasını atlar.
Filtre etiketi ve onay kutusu
<fieldset>
öğesinin doğrudan alt öğesi olarak ve formun 30ch
maksimum genişliği içinde yer alan etiket metni çok uzunsa kaydırılabilir. Metni kaydırmak harika bir özellik olsa da metin ve onay kutusu arasındaki hizalama hatası iyi bir özellik değildir. Bu işlem için Flexbox idealdir.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}

Animasyonlu ızgara
Düzen animasyonu Isotope tarafından yapılır. Etkileşimli sıralama ve filtreleme için yüksek performanslı ve güçlü bir eklenti.
JavaScript
JavaScript, düzenli bir animasyonlu ve etkileşimli ızgaranın düzenlenmesine yardımcı olmanın yanı sıra birkaç pürüzü gidermek için de kullanılır.
Kullanıcı girişini normalleştirme
Bu tasarımda, giriş sağlamanın iki farklı yolunu içeren bir form vardır ve bunlar aynı şekilde serileştirilmez. Ancak bazı JavaScript'lerle verileri normalleştirebiliriz.
<select>
öğe veri yapısını, gruplandırılmış onay kutuları yapısıyla eşleştirmeyi seçtim. Bunu yapmak için <select>
öğesine bir
input
etkinlik işleyici eklenir. 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önderebilirsiniz veya bu demoda olduğu gibi Isotope'a neye göre filtreleme yapacağını söyleyebilirsiniz.
Durum rolü öğesini tamamlama
Öğe yalnızca onay kutusu etkileşimine göre filtre sayısını hesaplayıp duyuruyor ancak sonuç sayısını da paylaşmanın ve <select>
öğe seçimlerinin de sayılmasını sağlamanın iyi bir fikir olduğunu düşündüm.
<select>
öğe seçimi counter()
içinde yansıtılır
Veri normalleştirme bölümünde, girişte zaten bir dinleyici oluşturulmuştu. Bu işlevin sonunda, seçilen filtrelerin sayısı ve bu filtrelerle ilgili sonuçların sayısı bilinir. Değerler, durum rolü öğesine şu şekilde iletilebilir.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Sonuçlar role="status"
öğesine yansıtılır.
:checked
, seçilen filtrelerin sayısını durum rolü öğesine iletmek için yerleşik bir yöntem sunar ancak filtrelenen sonuç sayısının görünürlüğü yoktur.
JavaScript, onay kutularıyla etkileşimi izleyebilir ve ızgarayı filtreledikten sonra textContent
öğesi gibi <select>
ekleyebilir.
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, "2 filtre 25 sonuç veriyor" duyurusunu tamamlıyor.
Artık mükemmel yardımcı teknoloji deneyimimiz, kullanıcılar nasıl etkileşim kurarsa kursun tüm kullanıcılara sunulacak.
Sonuç
Bunu nasıl yaptığımı öğrendiğinize göre, siz nasıl yapardınız? 🙂
Yaklaşımlarımızı çeşitlendirelim ve web'de içerik oluşturmanın tüm yollarını öğrenelim. Bir demo oluşturun, bağlantıları bana tweet atın. Ben de bu bağlantıları aşağıdaki topluluk remiksleri bölümüne ekleyeyim.
Topluluk remiksleri
Henüz burada gösterilecek bir şey yok.