Çoklu seçim bileşeni oluşturma

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.

Demo

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>.

Masaüstünde onay kutuları içeren kenar çubuğuyla açık ve koyu modu, mobil iOS ve Android&#39;de ise çoklu seçim öğesini gösteren karşılaştırma ekran görüntüsü.

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.

Android, iPhone ve iPad&#39;de Chrome&#39;daki çoklu seçim öğesinin ekran görüntüsü önizlemesi. iPad ve iPhone&#39;da çoklu seçim açıktır ve her cihazda ekran boyutuna göre optimize edilmiş benzersiz bir deneyim sunulur.

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>

Açıklama ve alan grubu öğeleri için bilgilendirici bir yer paylaşımı içeren ekran görüntüsü, renk ve öğe adını gösterir.

<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>

Çoklu seçim öğesinin masaüstünde oluşturulan ekran görüntüsü.

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.

Etkin filtrelerin sayısını duyuran macOS ekran okuyucusunun ekran görüntüsü.

İç 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:

Bir grup alanı ve açıklama için varsayılan stillerin ekran görüntüsü.

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.

Girişler arasındaki kenar boşluğunu gösteren ancak açıklamayı göstermeyen ekran görüntüsü.

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;
}
Onay işaretinin, çok satırlık bir sarmalama senaryosundaki ilk metin satırıyla nasıl hizalandığını gösteren ekran görüntüsü.
Bu Codepen'de daha fazla oynayın

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.

Hedefi ve normalleştirilmiş veri sonuçlarını gösteren DevTools JavaScript konsolunun ekran görüntüsü.

<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.

Sonuçları duyuran MacOS ekran okuyucusunun ekran görüntüsü.

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.