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çeneklerinin hızlı bir şekilde taranması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çime stil uygulanamaz ve yalnızca çok sayıda seçenek sunmaya uygun olmayan kompakt 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
'dir.
Ö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 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 varsayılan olarak hiçbir şey :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 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. 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
Etiketler ve onay kutuları listesi mobil cihazlarda ç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 ekranla yüksek düzeyde hassasiyetle etkileşime geçemeyeceğini belirtir. Birincil etkileşim dokunma olduğundan mobil cihazlarda işaretçi değeri genellikle coarse
olur. Masaüstü cihazlarda, fare veya başka bir yüksek hassasiyetli giriş cihazının bağlı olması yaygın olduğundan işaretçi değeri genellikle fine
olur.
Alan grupları
<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 bitişik kardeş 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şı olabilir. Metni satır sonuna sığdırmak iyi bir fikirdir ancak metin ile onay kutusunun hizasız olması iyi 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önderebilir veya bu demoda olduğu gibi Isotope'a hangi kritere göre filtreleme yapacağını bildirebilirsiniz.
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, durum rolü öğesine aşağıdaki gibi 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? 🙂
Yaklaşımlarımızı çeşitlendirelim ve web'de uygulama 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.