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ę.
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.
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.
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>
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>
Ś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.
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:
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.
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.](https://web.dev/static/articles/building/a-multi-select-component/image/screenshot-showing-the-c-b135285ef7d8a.png?authuser=7&hl=pl)
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.
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”.
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.