Kullanıcı deneyimlerini sıralamak ve filtrelemek için duyarlı, uyarlanabilir ve erişilebilir çoklu seçim bileşeni oluşturmaya dair temel bir genel bakış.
Bu yayında, çoklu seçim bileşeni oluşturmanın bir yolunu paylaşmak istiyorum. Demoyu deneyin.
Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:
Genel Bakış
Kullanıcılara genellikle öğeler (bazen çok sayıda öğe) sunulur. Bu durumlarda, çok fazla seçenek sunarak kullanıcıları bunaltmamak 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. Bunu, kullanıcıların seçebileceği veya seçimini kaldırabileceği öğe özelliklerini sunarak yapar. Böylece sonuçları azaltır ve dolayısıyla seçim yükü de azalır.
Etkileşimler
Amaç, tüm kullanıcılar ve farklı giriş türleri için filtre seçenekleri arasında hızlı geçiş yapılmasını sağlamaktır. Bu, uyarlanabilir ve duyarlı bir çift bileşenle yayınlanır. Masaüstü, klavye ve ekran okuyucular için onay kutularından oluşan geleneksel bir kenar çubuğu ve dokunmatik kullanıcılar için bir <select
multiple>
.
Yerleşik çoklu seçimi masaüstü için değil, dokunmatik ekran için kullanma kararı hem iş tasarrufu sağlıyor hem de iş yaratıyor. Ancak tüm duyarlı deneyimi tek bir bileşende oluşturmaktan daha az kod borcuyla uygun deneyimler sunduğunu düşünüyorum.
Dokunma
Dokunma bileşeni, alandan tasarruf sağlar ve mobil cihazlarda kullanıcı etkileşiminin doğruluğuna yardımcı olur. Onay kutularının bulunduğu tüm kenar çubuğunu yerleşik bir yer paylaşımlı dokunma deneyimine <select>
sığdırarak yer tasarrufu sağlar. Sistem tarafından sağlanan büyük bir dokunmatik yer paylaşımı deneyimi göstererek giriş doğruluğunu artırır.
Klavye ve oyun kumandası
Aşağıda, klavyeden <select multiple>
simgesinin nasıl kullanılacağı gösterilmektedir.
Bu yerleşik çoklu seçimin stili ayarlanamaz ve yalnızca çok fazla seçenek sunmaya uygun olmayan küçük bir düzende sunulur. Bu küçük kutuda seçeneklerin kapsamını göremediğinizi fark ettiniz mi? Boyutunu değiştirebilseniz de onay kutularının bulunduğu 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 tabloyu filtrelemek için kullanılır ancak bir sunucuya da gönderilebilir.
<form>
</form>
Onay kutuları bileşeni
Onay kutusu grupları bir <fieldset>
öğesine sarmalanmış ve <legend>
ile belirtilmiş olmalıdır.
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ırmayı yaptıktan sonra her filtre için bir <label>
ve <input type="checkbox">
ekleyin. Ben, CSS gap
mülkünün etiketler birden çok satıra yayıldığında bunları eşit aralıklarla yerleştirebilmesi ve hizalamayı koruyabilmesi için etiketleri <div>
içine sarmaladım.
<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 öğe seçmesine izin verilir. Bu, etkileşimi radyo listesinden onay kutusu listesine değiştirmek gibidir.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Bir <select>
içinde grup etiketlemek ve oluşturmak için <optgroup>
öğesini kullanın ve öğeye bir 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>
Ardından 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ı teknolojileri bilgilendirmek için girişleri sayaçlarla izleme
Ekran okuyucular ve diğer yardımcı teknolojiler için filtrelerin sayısını takip etmek ve korumak amacıyla bu kullanıcı deneyiminde durum rolü tekniği kullanılır. YouTube videosunda
bu özellik gösterilmektedir. 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 olarak okur. Kullanıcılar onay kutularıyla etkileşime geçtiğinde içerikleri CSS sayaçları ile güncelleyebiliriz. Bunun için öncelikle girişler ve durum öğesinin üst öğesinde bir adı olan bir sayaç oluşturmamız gerekir.
aside {
counter-reset: filters;
}
Varsayılan olarak sayı 0
olur. Bu tasarımda hiçbir şey varsayılan olarak :checked
değildir.
Ardından, yeni oluşturulan sayacımızı artırmak için <aside>
öğesinin :checked
olan alt öğelerini hedefliyoruz. 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 toplamından haberdardır ve durum rolü öğesi boştur ve değerler beklemektedir. CSS, sayımı bellekte tuttuğu için counter()
işlevi, sözde öğe içeriklerinden değere erişmenize olanak tanır:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Durum rolü öğesinin HTML'si artık ekran okuyucuya "2 filtre"yi duyuracaktır. Bu iyi bir başlangıç ancak daha iyisini yapabiliriz. Örneğin, filtrelerin güncellediği sonuçların sayısını paylaşabiliriz. Sayaçların yapabileceği işlemlerin dışında olduğu için bu işlemi JavaScript'ten yapacağız.
İç içe yerleştirme heyecanı
Tüm mantığı tek bir bloğa yerleştirebildiğim için sayıcı algoritması, CSS iç içe yerleştirme-1 ile harika bir deneyim oldu. Okuma ve güncelleme için taşınabilir ve merkezidir.
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şeni içindir.
Form
Kullanıcılar için okunabilirliği ve taranabilirliği optimize etmek amacıyla forma maksimum 30 karakter genişliği verilir. Bu sayede her filtre etiketi için optik bir satır genişliği belirlenir. Form, grup kutularını birbirinden ayırmak için ızgara düzenini ve gap
mülkünü 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ıyla ekranla yüksek miktarda hassasiyetle etkileşimde bulunamayacağını belirtir. Birincil etkileşim dokunma olduğundan mobil cihazlarda işaretçi değeri genellikle coarse
olur. Masaüstü cihazlarda işaretçi değeri genellikle fine
şeklindedir. Bunun nedeni, bir fare veya yüksek hassasiyetli başka bir giriş cihazının bağlanması yaygındır.
Alan kümeleri
<legend>
içeren <fieldset>
öğesinin varsayılan stili ve düzeni benzersizdir:
Normalde, alt öğelerimin aralığını ayarlamak için gap
mülkünü kullanırdım ancak <legend>
'un benzersiz konumlandırması, eşit aralıklı bir alt öğe grubu oluşturmayı zorlaştırıyor. gap
yerine, yakındaki eşdüzey seçici ve margin-block-start
kullanılır.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Bu sayede <legend>
, yalnızca <div>
çocuklarını hedefleyerek alanının ayarlanmasını atlar.
Filtre etiketi ve onay kutusu
Bir <fieldset>
öğesinin doğrudan alt öğesi olarak ve formun 30ch
öğesinin maksimum genişliği içinde yer alan etiket metni çok uzunsa satır başı ekleyebilir. Metnin sarmalanması iyidir, ancak metin ile
onay kutusu arasındaki uyuşmazlık değildir. Flexbox bu amaç için 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 performanslı ve güçlü bir eklenti.
JavaScript
JavaScript, düzgün animasyonlu ve etkileşimli bir ızgara oluşturmanın yanı sıra bazı kusurları düzeltmek için de kullanılır.
Kullanıcı girişini normalleştirme
Bu tasarımda, giriş sağlamanın iki farklı yolu olan bir form vardır ve bu girişler aynı şekilde dizilenmez. Ancak bazı JavaScript'lerle verileri normalleştirebiliriz.
<select>
öğesi veri yapısını gruplandırılmış onay kutuları yapısıyla uyumlu hale getirmeyi seçtim. Bunu yapmak için <select>
öğesine bir input
etkinlik dinleyicisi eklenir. Bu noktada selectedOptions
ile 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 veya bu demoda Isotope'a neye göre filtreleme yapılacağı konusunda talimat verebilirsiniz.
Durum rolü öğesini tamamlama
Öğe, yalnızca onay kutusu etkileşimine göre filtre sayısını sayar ve duyurur ancak sonuçların sayısını da paylaşmanın ve <select>
öğe seçeneklerinin de sayılmasını sağlamanın iyi bir fikir olduğunu düşündüm.
<select>
öğesi seçimi counter()
'a yansıtıldı
Veri normalleştirme bölümünde, girişte zaten bir dinleyici oluşturuldu. Bu işlevin sonunda, seçilen filtrelerin sayısı ve bu filtrelere ait sonuç sayısı bilinir. Değerler, bunun gibi durum rolü öğesine iletilebilir.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
role="status"
öğesine yansıtılan sonuçlar
:checked
, seçilen filtrelerin sayısını durum rolü öğesine iletmenin yerleşik bir yolunu sağlar ancak filtrelenen sonuç sayısının görünürlüğü yoktur.
JavaScript, onay kutularıyla etkileşimi izleyebilir ve tabloyu filtreledikten sonra <select>
öğesi gibi textContent
ekler.
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, "25 sonuç veren 2 filtre" duyurusunu tamamlar.
Artık mükemmel yardımcı teknoloji deneyimimiz, onunla etkileşime geçen tüm kullanıcılara sunulacaktır.
Sonuç
Bunu nasıl yaptığımı öğrendiğinize göre, siz ne yapardınız? 🙂
Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim. Bir demo oluşturun, bağlantılarını bana tweetleyin. Ardından, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.
Topluluk remiksleri
Henüz burada gösterilecek bir şey yok.