Tworzenie komponentu wielokrotnego wyboru

Podstawowe informacje o tworzeniu elastycznego, adaptacyjnego i dostępnego komponentu wielokrotnego wyboru do sortowania i filtrowania treści dla użytkowników.

W tym poście pokażę, jak mogę utworzyć komponent wielokrotnego wyboru. Zobacz prezentację.

Demonstracja

Jeśli wolisz film, oto wersja tego posta na YouTube:

Przegląd

Użytkownicy często mają w zasięgu ręki produkty, a czasem dużo produktów. W takich przypadkach warto zastanowić się nad skróceniem listy, aby uniknąć nadmiernego wyboru. W tym poście objaśniamy sposób, w jaki można ograniczyć liczbę dostępnych opcji filtrowania w interfejsie filtrowania. Odbywa się to przez wyświetlanie atrybutów produktów, które użytkownicy mogą zaznaczać lub odznaczać, co ogranicza liczbę wyników i zmniejsza przeciążenie możliwości wyboru.

Interactions

Ma to na celu umożliwienie szybkiego poruszania się po opcjach filtrowania wszystkim użytkownikom i ich różnym typom danych wejściowych. Dane te będą dostarczane z elastyczną parą komponentów. Tradycyjny pasek boczny z polami wyboru dla komputerów, klawiatur i czytników ekranu oraz <select multiple> dla użytkowników dotykowych.

Zrzut ekranu z porównaniem jasnego i ciemnego obrazu na komputerze z paskiem wyboru z polami wyboru w porównaniu z elementami wyboru na urządzeniach mobilnych z iOS i Androidem.

Decyzja o wykorzystaniu wbudowanego wyboru wielokrotnego wyboru w przypadku reklam dotykowych, a nie komputerów, pozwala zaoszczędzić czas i zmniejszyć nakład pracy. Uważam jednak, że jest to bardziej przydatne rozwiązanie, które wymaga mniej kodu niż tworzenie całego środowiska responsywnego w jednym komponencie.

Dotyk

Komponent dotykowy oszczędza miejsce i zwiększa dokładność interakcji z użytkownikiem na urządzeniach mobilnych. Oszczędza miejsce, zwijając cały pasek boczny pól wyboru we wbudowaną nakładkę dotykową <select>. Pomaga on poprawić dokładność danych wejściowych, wyświetlając dużą nakładkę dotykową oferowaną przez system.

Zrzut ekranu z podglądem elementu wielokrotnego wyboru w Chrome na urządzeniach z Androidem, iPhonie i iPadzie iPad i iPhone mają otwarty przełącznik wielokrotnego wyboru, a każdy z nich korzysta z unikalnych funkcji zoptymalizowanych pod kątem rozmiaru ekranu.

Klawiatura i pad do gier

Poniżej znajdziesz przykład korzystania z <select multiple> z poziomu klawiatury.

Tego wbudowanego wyboru wielokrotnego wyboru nie można określić. Jest on oferowany tylko w zwartym układzie, w którym nie ma zbyt wielu opcji do wyboru. To małe pudełko, w którym można nie dostrzec szerokiego zakresu opcji. Choć można zmienić jego rozmiar, wciąż jest on mniej użyteczny jak pasek boczny pól wyboru.

Markup

Oba komponenty będą znajdować się w tym samym elemencie <form>. Wyniki tego formularza, niezależnie od tego, czy są pola wyboru czy wielokrotnego wyboru, będą obserwowane i używane do filtrowania siatki, ale mogą być również przesyłane na serwer.

<form>

</form>

Komponent Pola wyboru

Grupy pól wyboru powinny znajdować się wewnątrz elementu <fieldset> i dać mu <legend>. Jeśli kod HTML ma taką strukturę, czytniki ekranu i FormData automatycznie rozpoznają relację między elementami.

<form>
  <fieldset>
    <legend>New</legend>
    … checkboxes …
  </fieldset>
</form>

Po grupowaniu dodaj <label> i <input type="checkbox"> do każdego filtra. Zdecydowałem się zawijać je w elemencie <div>, aby właściwość CSS gap mogła je równomiernie rozmieścić i utrzymać wyrównanie, gdy etykiety przejdą wiele wierszy.

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

Zrzut ekranu z nakładką informacyjną na temat legendy i elementów zbioru pól, pokazujący kolor i nazwę elementu.

Komponent <select multiple>

Rzadko używana funkcja elementu <select> to multiple. Jeśli użyjesz tego atrybutu z elementem <select>, użytkownik może wybrać wiele elementów z listy. Przypomina to zamianę interakcji z listy radiowej w listę pól wyboru.

<form>
  <select multiple="true" title="Filter results by category">
    …
  </select>
</form>

Aby oznaczyć etykietą i utworzyć grupy w elemencie <select>, użyj elementu <optgroup> i nadaj mu atrybut i wartość label. Ten element i wartość atrybutu są podobne do elementów <fieldset> i <legend>.

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      …
    </optgroup>
  </select>
</form>

Teraz dodaj elementy <option> filtra.

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

Zrzut ekranu z renderowaniem na komputerze elementu wielokrotnego wyboru.

Śledzenie danych wejściowych za pomocą liczników, aby przekazywać informacje do technologii wspomagającej osoby z niepełnosprawnością

Technika roli stanu jest wykorzystywana w tym środowisku. Służy do śledzenia i utrzymywania zgodności filtrów czytników ekranu i innych technologii wspomagających osoby z niepełnosprawnością. Film w YouTube pokazuje tę funkcję. Integracja zaczyna się od kodu HTML i atrybutu role="status".

<div role="status" class="sr-only" id="applied-filters"></div>

Ten element będzie odczytywać na głos zmiany wprowadzone w treści. W miarę interakcji użytkowników z polami wyboru możemy aktualizować ich zawartość za pomocą liczników CSS. W tym celu musimy najpierw utworzyć licznik z nazwą elementu nadrzędnego elementu wejściowego i stanu.

aside {
  counter-reset: filters;
}

Domyślnie liczba będzie wynosić 0, co oznacza, że w tym projekcie nie ma wartości :checked.

Następnie, aby zwiększyć nowo utworzony licznik, będziemy kierować reklamy do elementów podrzędnych elementu <aside>, który ma wartość :checked. Gdy użytkownik zmieni stan danych wejściowych, licznik filters będzie zliczany.

aside :checked {
  counter-increment: filters;
}

CSS wie teraz o ogólnej liczbie elementów w interfejsie pola wyboru, a element roli stanu jest pusty i oczekuje na wartości. CSS przechowuje wyniki w pamięci, dlatego funkcja counter() umożliwia dostęp do wartości z treści pseudoelementu:

aside #applied-filters::before {
  content: counter(filters) " filters ";
}

Kod HTML elementu roli stanu będzie informował czytnik ekranu o treści „2 filtry”. To dobry początek, ale możemy zrobić więcej, na przykład udostępnić podsumowanie wyników zaktualizowanych przez filtry. Zajmiemy się tym w przypadku JavaScriptu, bo to robimy poza możliwościami liczników.

Zrzut ekranu czytnika ekranu w systemie macOS z informacją o liczbie aktywnych filtrów.

Początek ekscytacji

Algorytm liczników sprawdza się świetnie w przypadku zagnieżdżania arkusza CSS-1, ponieważ udało mi się zebrać wszystkie elementy w jednym bloku. Poręczny i scentralizowany do czytania i aktualizowania.

aside {
  counter-reset: filters;

  & :checked {
    counter-increment: filters;
  }

  & #applied-filters::before {
    content: counter(filters) " filters ";
  }
}

Układy

W tej sekcji opisujemy układy między dwoma komponentami. Większość stylów układu dotyczy komponentu pola wyboru na komputerze.

Formularz

Aby użytkownicy mogli łatwiej przeglądać formularz, jego maksymalna szerokość wynosi 30 znaków, co oznacza zasadniczo ustawienie optycznej szerokości linii dla każdej etykiety filtra. Formularz używa układu siatki i właściwości gap do rozdzielania zbiorów pól.

form {
  display: grid;
  gap: 2ch;
  max-inline-size: 30ch;
}

Element <select>

Zarówno lista etykiet, jak i pola wyboru zajmują za dużo miejsca na urządzeniach mobilnych. Dlatego też układ sprawdza główne urządzenie wskazujące użytkownika, aby zmienić sposób obsługi dotyku.

@media (pointer: coarse) {
  select[multiple] {
    display: block;
  }
}

Wartość coarse oznacza, że użytkownik nie może z dużą precyzją wchodzić w interakcję z ekranem za pomocą swojego głównego urządzenia wejściowego. Na urządzeniu mobilnym wartość wskaźnika to często coarse, ponieważ główna interakcja to dotyk. Na komputerze wartość wskaźnika to często fine, ponieważ często jest podłączona mysz lub inne urządzenie wejściowe o dużej dokładności.

Zbiory pól

Domyślny styl i układ elementu <fieldset> z elementem <legend> jest unikalny:

Zrzut ekranu przedstawiający domyślne style zbioru pól i legendy.

Normalnie, aby rozmieścić elementy podrzędne, używam właściwości gap, ale unikalne położenie obiektu <legend> utrudnia utworzenie równomiernego zestawu elementów podrzędnych. Zamiast gap są używane sąsiadujące selektory równorzędne i margin-block-start.

fieldset {
  padding: 2ch;

  & > div + div {
    margin-block-start: 2ch;
  }
}

Dzięki temu <legend> nie będzie dostosowywana do miejsca, w którym jest kierowana tylko na <div> elementów podrzędnych.

Zrzut ekranu przedstawiający odstępy między marginesami, ale bez legendy.

Etykieta i pole wyboru filtra

Jeśli tekst etykiety jest bezpośrednim elementem podrzędnym elementu <fieldset> i nie przekracza maksymalnej szerokości 30ch formularza, może on się zawijać, jeśli jest zbyt długi. Zawijanie tekstu jest przydatne, ale niedopasowanie tekstu do pola wyboru. Idealnie sprawdza się w tym przypadku Flexbox.

fieldset > div {
  display: flex;
  gap: 2ch;
  align-items: baseline;
}
Zrzut ekranu pokazujący, jak znacznik dopasowuje się do pierwszego wiersza tekstu przy zawijaniu wielu wierszy.
Odtwórz więcej w tym Codepen

Animowana siatka

Animacja układu jest wykonywana przez Isotope. Wydajna i wydajna wtyczka do interaktywnego sortowania i filtrowania.

JavaScript

JavaScript nie tylko ułatwia administrowanie animowaną, interaktywną siatką, ale też pozwala dopracować kilka surowych elementów.

Normalizowanie danych wejściowych użytkownika

Ten projekt składa się z jednego formularza z dwoma różnymi sposobami wprowadzania danych wejściowych i nie serializuje tych samych danych. JavaScript pozwala jednak znormalizować dane.

Zrzut ekranu przedstawiający konsolę JavaScript w Narzędziach deweloperskich, która pokazuje cel i znormalizowane wyniki danych.

Wybrałem(-am) wyrównanie struktury danych elementu <select> do struktury zgrupowanych pól wyboru. W tym celu input detektor zdarzeń jest dodawany do elementu <select>, w którym momencie selectedOptions jest zmapowany.

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
  }, [])
})

Możesz teraz bezpiecznie przesłać formularz. W przypadku tej prezentacji wskaż izotop, według którego chcesz filtrować dane.

Kończenie elementu roli stanu

Element tylko zlicza i informuje o liczbie filtrów na podstawie interakcji z polem wyboru, ale uznałem, że warto dodatkowo podzielić się liczbą wyników i zadbać o uwzględnienie wybranych elementów <select>.

Wybór elementu „<select>” jest odzwierciedlany w: counter()

W sekcji normalizacji danych detektor został już utworzony na podstawie danych wejściowych. Liczba wybranych filtrów i liczba wyników dla tych filtrów są już znane. Wartości można przekazywać do elementu roli stanu w ten sposób.

let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length

Wyniki są odzwierciedlane w elemencie role="status"

Funkcja :checked udostępnia wbudowany sposób przekazywania liczby wybranych filtrów do elementu roli stanu, ale nie ma wglądu w filtrowaną liczbę wyników. JavaScript może wykrywać interakcje z polami wyboru i po odfiltrowaniu siatki dodać textContent w taki sam sposób jak element <select>.

document
  .querySelector('aside form')
  .addEventListener('input', e => {
    // isotope demo code
    let filterResults = IsotopeGrid.getFilteredItemElements().length
    document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})

Łącznie opublikowano ogłoszenie „2 filtry dają 25 wyników”.

Zrzut ekranu z czytnikiem ekranu w systemie macOS z ogłoszeniem wyników.

Teraz wszyscy użytkownicy będą mogli korzystać z naszej doskonałej technologii wspomagającej osoby z niepełnosprawnością niezależnie od tego, w jaki sposób z niej korzystają.

Podsumowanie

Wiesz już, jak to zrobiłem, więc jak to zrobisz 🙂

Stwórzmy różne metody i nauczmy się wszystkiego, jak rozwijać się w internecie. Utwórz demonstrację i udostępnię mi linki na Twitterze, a dodam ją do sekcji remiksów w ramach społeczności poniżej.

Remiksy społeczności

Nic tu jeszcze nie ma.