Podstawowy przegląd sposobów tworzenia responsywnego, elastycznego i dostępnego komponentu z wieloznacznikiem do sortowania i filtrowania treści.
W tym poście przedstawię sposoby tworzenia komponentu wielokrotnego wyboru. Wypróbuj wersję demonstracyjną.
Jeśli wolisz film, oto wersja tego posta w YouTube:
Omówienie
Użytkownicy często widzą wiele produktów, a w takich przypadkach warto udostępnić sposób na skrócenie listy, aby zapobiec nadmiernej ilości opcji. W tym poście na blogu omawiamy interfejs filtrowania jako sposób na ograniczenie liczby opcji. Robi to, prezentując atrybuty produktów, które użytkownicy mogą zaznaczać lub odznaczać, ograniczając liczbę wyników i tym samym ograniczając ilość wyborów.
Interakcje
Celem jest umożliwienie szybkiego przeglądania opcji filtrowania wszystkim użytkownikom i przy użyciu różnych typów danych wejściowych. Będzie to możliwe dzięki parze komponentów, które są elastyczne i dopasowują się do treści. Tradycyjny pasek boczny z polami wyboru dotyczącymi komputerów, klawiatury i czytników ekranu oraz <select
multiple>
dla użytkowników dotykowych.
Decyzja o użyciu wbudowanego elementu wyboru wielokrotnego w przypadku urządzeń dotykowych, a nie komputerów stacjonarnych, pozwala zaoszczędzić czas i wymaga dodatkowych działań, ale zapewnia odpowiednie działanie przy mniejszym zadłużeniu kodu niż tworzenie całego interfejsu responsywnego w jednym komponencie.
Dotyk
Komponent dotykowy oszczędza miejsce i pomaga zwiększyć dokładność interakcji na urządzeniach mobilnych. Oszczędza miejsce, ponieważ pozwala zwijać cały pasek boczny z polem wyboru do wbudowanego <select>
przeźroczystego okienka dotykowego. Pomaga to zwiększyć dokładność wprowadzania,
wyświetlając dużą nakładkę dotykową.
Klawiatura i kontroler
Poniżej pokazujemy, jak używać <select multiple>
na klawiaturze.
Ta wbudowana opcja wyboru wielokrotnego nie może być stylizowana i jest dostępna tylko w kompaktowym układzie, który nie nadaje się do przedstawiania wielu opcji. Widzisz, że w tym małym polu nie widać wszystkich opcji? Chociaż możesz zmieniać jego rozmiar, w dalszym ciągu nie jest tak przydatna jak pasek boczny z polami wyboru.
Znacznik
Oba komponenty będą się znajdowały w tym samym elemencie <form>
. Wyniki tego formularza, niezależnie od tego, czy są to pola wyboru, czy pola wielokrotnego wyboru, będą obserwowane i używane do filtrowania siatki, ale mogą też zostać przesłane na serwer.
<form>
</form>
Komponent Pola wyboru
Grupy pól wyboru powinny być umieszczone w element <fieldset>
i przydzielony do <legend>
.
Gdy kod HTML jest tak sformatowany, czytniki ekranu i FormData automatycznie rozumieją relacje między elementami.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Po utworzeniu grupowania dodaj <label>
i <input type="checkbox">
do każdego filtra. Ja użyłem elementu <div>
, aby właściwości CSS gap
mogły je rozmieścić równomiernie i utrzymać wyrównanie, gdy etykiety będą miały kilka 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żywaną funkcją elementu <select>
jest multiple
.
Jeśli atrybut jest używany z elementem <select>
, użytkownik może wybrać wiele elementów z listy. To jak zmiana interakcji z listy rozwijanej na listę z polami wyboru.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Aby oznaczyć i utworzyć grupy wewnątrz elementu <select>
, użyj elementu <optgroup>
i przypisz mu atrybut label
oraz wartość. 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>
do 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 w celu informowania technologii wspomagających
W tym przypadku do śledzenia i utrzymywania liczby filtrów dla czytników ekranu oraz innych technologii wspomagających stosuje się technikę statusu roli. Film w YouTube
demonstruje tę funkcję. Integracja zaczyna się od kodu HTML i atrybutu role="status"
.
<div role="status" class="sr-only" id="applied-filters"></div>
Ten element odczyta na głos zmiany wprowadzone w treści. Możemy aktualizować zawartość za pomocą liczników CSS, gdy użytkownicy będą korzystać z pól wyboru. W tym celu trzeba najpierw utworzyć licznik z nazwą w elemencie nadrzędnym danych wejściowych i elementów stanu.
aside {
counter-reset: filters;
}
Domyślnie liczba wynosi 0
, co jest bardzo dobre. Domyślnie w tym projekcie nic nie jest określone jako :checked
.
Następnie, aby zwiększyć wartość nowo utworzonego licznika, będziemy kierować reklamy na elementy podrzędne elementu <aside>
, które są :checked
. Gdy użytkownik zmienia stan danych wejściowych, licznik filters
będzie się zwiększał.
aside :checked {
counter-increment: filters;
}
CSS wie teraz, że ogólna liczba pól wyboru w interfejsie jest równa 0, a element stanu role jest pusty i oczekuje na wartości. Ponieważ CSS przechowuje wynik w pamięci, funkcja counter()
umożliwia dostęp do wartości z zawartości pseudoelementu:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Kod HTML elementu roli stanu będzie teraz ogłaszać w narzędziach do odczytu ekranu „2 filtry”. To dobry początek, ale możemy zrobić więcej, np. udostępnić podsumowanie wyników zaktualizowanych przez filtry. Wykorzystamy do tego JavaScript, ponieważ nie można tego zrobić za pomocą liczników.
Tworzenie emocji
Algorytm liczników świetnie współpracował z CSS nesting-1, ponieważ udało mi się umieścić całą logikę w jednym bloku. Przenośna i scentralizowana funkcja odczytu i aktualizowania.
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
Układy
W tej sekcji opisano układy między tymi 2 komponentami. Większość stylów układu dotyczy komponentu pola wyboru na komputerze.
Formularz
Aby zoptymalizować czytelność i czytelność dla użytkowników, formularz ma maksymalną szerokość 30 znaków, co zasadniczo ustawia szerokość linii optycznych dla każdej etykiety filtra. Formularz używa układu siatki i właściwości gap
, aby rozmieszczać pola danych w odstępach.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
Element <select>
Lista etykiet i pola wyboru zajmują zbyt dużo miejsca na urządzeniach mobilnych. Dlatego układ sprawdza, jakie urządzenie wskazujące jest używane przez użytkownika, aby zmienić sposób obsługi dotykowej.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
Wartość coarse
oznacza, że użytkownik nie będzie mógł sterować ekranem z dużą precyzją za pomocą głównego urządzenia wejściowego. Na urządzeniu mobilnym wartość wskaźnika często wynosi coarse
, ponieważ główną metodą interakcji jest dotyk. Na komputerze wartość wskaźnika często wynosi fine
, ponieważ często jest podłączona mysz lub inne urządzenie wejściowe o wysokiej precyzji.
Pola zbiorcze
Domyślny styl i układ elementu <fieldset>
z atrybutem <legend>
jest unikalny:
Normalnie, aby rozmieścić elementy podrzędne, użyjesz właściwości gap
, ale unikalne położenie elementu <legend>
utrudnia utworzenie równomiernie rozmieszczonych elementów podrzędnych. Zamiast gap
używane są selektor sąsiedniego elementu brata i margin-block-start
.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
W ten sposób nie trzeba dostosowywać miejsca dla <legend>
, kierując go tylko do dzieci z grupy <div>
.
Etykieta i pole wyboru filtra
Jako element podrzędny elementu <fieldset>
i mieszczący się w maksymalnej szerokości elementu 30ch
, tekst etykiety może się przewijać, jeśli jest zbyt długi. Zawijanie tekstu jest świetne, ale niedopasowanie między tekstem a polem wyboru nie. Do tego celu idealnie nadaje się flexbox.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
Animowana siatka
Animację układu wykonuje Isotope. Wydajny i zaawansowany wtyczka do interaktywnego sortowania i filtrowania.
JavaScript
JavaScript pomaga nie tylko w zarządzaniu schludną animowaną, interaktywną siatką, ale także w dopracowaniu drobnych elementów.
Normalizacja danych wejściowych użytkownika
Ten projekt ma 1 formularz z 2 różnymi sposobami wprowadzania danych, które nie są serializowane. Używając kodu JavaScript, możemy normalizować dane.
Zdecydowaliśmy się dopasować strukturę danych elementu <select>
do struktury pól wyboru w grupach. W tym celu do elementu <select>
dodawany jest detektor zdarzenia input
, który jest następnie mapowany na element selectedOptions
.
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
}, [])
})
Teraz możesz bezpiecznie przesłać formularz. W przypadku tej wersji demonstracyjnej możesz zapytać Isotope, jak ma filtrować dane.
Kończenie elementu roli stanu
Element zlicza i podaje liczbę filtrów tylko na podstawie interakcji z polem wyboru, ale uznaliśmy, że warto dodatkowo udostępnić liczbę wyników i upewnić się, że uwzględnione są też elementy <select>
.
Wybór elementu <select>
widoczny w tabeli counter()
W sekcji normalizacji danych na podstawie danych wejściowych został już utworzony odbiorca. Na końcu tej funkcji znana jest liczba wybranych filtrów i liczba wyników dla tych filtrów. W ten sposób wartości można przekazywać do elementu „stan”.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Wyniki odzwierciedlone w elemencie role="status"
:checked
zapewnia wbudowany sposób przekazywania liczby wybranych filtrów do elementu roli stanu, ale nie zapewnia widoczności liczby wyników po odfiltrowaniu.
Kod JavaScript może sprawdzać interakcje z polami wyboru i po odfiltrowaniu siatki dodawać textContent
, tak jak to robi 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`
})
W ten sposób zakończymy proces wdrażania ogłoszenia „2 filtry, które dają 25 wyników”.
Teraz wszyscy użytkownicy będą mogli korzystać z naszej doskonałej technologii wspomagającej.
Podsumowanie
Wiesz już, jak to zrobiłem. Jak Ty? 🙂
Zróżnicujemy nasze podejścia i poznamy wszystkie sposoby tworzenia stron internetowych. Utwórz wersję demonstracyjną, wyślij mi linki, a ja dodam je do sekcji z remiksami społeczności.
Remiksy społeczności
Na razie jest tu pusto