Eine grundlegende Übersicht dazu, wie Sie eine responsive, adaptive und barrierefreie Komponente mit Mehrfachauswahl für Sortier- und Filterfunktionen erstellen.
In diesem Beitrag möchte ich meine Überlegungen zur Entwicklung einer Komponente mit Mehrfachauswahl vorstellen. Demo ansehen
Wenn du lieber ein Video ansehen möchtest, findest du hier eine YouTube-Version dieses Beitrags:
Übersicht
Nutzer sehen oft viele Elemente, manchmal sehr viele. In diesen Fällen kann es sinnvoll sein, die Liste zu reduzieren, um eine Überforderung durch die Auswahl zu vermeiden. In diesem Blogpost wird die Benutzeroberfläche für Filter als Möglichkeit zur Reduzierung der Auswahlmöglichkeiten untersucht. Dazu werden Artikelattribute präsentiert, die Nutzer auswählen oder abwählen können. So werden die Ergebnisse reduziert und die Auswahlmöglichkeiten werden übersichtlicher.
Interaktionen
Ziel ist es, allen Nutzern und ihren unterschiedlichen Eingabetypen eine schnelle Navigation durch die Filteroptionen zu ermöglichen. Dazu werden anpassungsfähige und responsive Komponenten verwendet. Eine herkömmliche Seitenleiste mit Kästchen für Desktop, Tastatur und Screenreader sowie ein <select
multiple>
für Touchscreen-Nutzer.
Die Entscheidung, die integrierte Mehrfachauswahl für Touch-Geräte und nicht für Desktop-Geräte zu verwenden, spart Arbeit und verursacht Arbeit. Ich glaube jedoch, dass sie angemessene Nutzerfreundlichkeit mit weniger Code-Schulden bietet als die Entwicklung der gesamten responsiven Benutzeroberfläche in einer Komponente.
Berührung
Die Touch-Komponente spart Platz und trägt zur Genauigkeit der Nutzerinteraktion auf Mobilgeräten bei. Dadurch wird Platz gespart, da eine ganze Seitenleiste mit Kästchen in ein integriertes <select>
-Overlay umgewandelt wird, das per Touch bedient werden kann. Das System bietet eine große Touch-Overlay-Oberfläche, die die Eingabegenauigkeit verbessert.
Tastatur und Gamepad
Unten sehen Sie, wie Sie ein <select multiple>
über die Tastatur eingeben.
Diese integrierte Mehrfachauswahl kann nicht formatiert werden und ist nur in einem kompakten Layout verfügbar, das sich nicht für die Darstellung vieler Optionen eignet. Sehen Sie, wie man in diesem kleinen Feld nicht wirklich die Vielfalt der Optionen erkennen kann? Sie können zwar die Größe ändern, aber es ist immer noch nicht so benutzerfreundlich wie eine Seitenleiste mit Kästchen.
Markieren & Zeichnen
Beide Komponenten sind im selben <form>
-Element enthalten. Die Ergebnisse dieses Formulars, unabhängig davon, ob es sich um Kästchen oder eine Mehrfachauswahl handelt, werden beobachtet und zum Filtern des Rasters verwendet, können aber auch an einen Server gesendet werden.
<form>
</form>
Komponente „Kästchen“
Gruppen von Kästchen sollten in ein <fieldset>
-Element eingeschlossen und mit einem <legend>
versehen werden.
Wenn HTML so strukturiert ist, erkennen Screenreader und FormData die Beziehung der Elemente automatisch.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Fügen Sie nach der Gruppierung für jeden Filter ein <label>
und ein <input type="checkbox">
hinzu. Ich habe sie in ein <div>
-Tag eingeschlossen, damit die CSS-Eigenschaft gap
sie gleichmäßig verteilen und die Ausrichtung beibehalten kann, wenn Labels mehrzeilig werden.
<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>
-Komponente
Eine selten verwendete Funktion des <select>
-Elements ist multiple
.
Wenn das Attribut mit einem <select>
-Element verwendet wird, kann der Nutzer mehrere Elemente aus der Liste auswählen. Das ist so, als würden Sie die Interaktion von einer Optionsfeldliste in eine Checkboxliste ändern.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Wenn Sie innerhalb eines <select>
Labels und Gruppen erstellen möchten, verwenden Sie das Element <optgroup>
und weisen Sie ihm ein label
-Attribut und einen Wert zu. Dieses Element und der Attributwert ähneln den Elementen <fieldset>
und <legend>
.
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
…
</optgroup>
</select>
</form>
Fügen Sie nun die <option>
-Elemente für den Filter hinzu.
<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>
Eingabe mit Zählern verfolgen, um Hilfstechnologien zu unterstützen
Die Statusrolle wird in dieser Benutzeroberfläche verwendet, um die Anzahl der Filter für Screenreader und andere assistive Technologien zu erfassen und zu verwalten. Das YouTube-Video zeigt die Funktion. Die Integration beginnt mit HTML und dem Attribut role="status"
.
<div role="status" class="sr-only" id="applied-filters"></div>
Dieses Element liest Änderungen am Inhalt vor. Wir können den Inhalt mit CSS-Zählern aktualisieren, wenn Nutzer mit den Kästchen interagieren. Dazu müssen wir zuerst einen Zähler mit einem Namen für ein übergeordnetes Element der Eingabe- und Statuselemente erstellen.
aside {
counter-reset: filters;
}
Standardmäßig ist die Anzahl 0
. Das ist gut, denn in diesem Design ist standardmäßig nichts :checked
.
Als Nächstes müssen wir den neu erstellten Zähler erhöhen. Dazu richten wir uns auf untergeordnete Elemente des <aside>
-Elements aus, die :checked
sind. Wenn der Nutzer den Status der Eingaben ändert, wird der filters
-Zähler hochgezählt.
aside :checked {
counter-increment: filters;
}
CSS ist jetzt über die allgemeine Anzahl der Checkbox-Benutzeroberfläche informiert und das Statusrollen-Element ist leer und wartet auf Werte. Da CSS die Zählung im Arbeitsspeicher verwaltet, kann mit der Funktion counter()
auf den Wert aus dem Inhalt des Pseudoelements zugegriffen werden:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Die HTML für das Statusrollenelement gibt jetzt „2 Filter“ für einen Screenreader aus. Das ist ein guter Anfang, aber wir können noch mehr tun, z. B. die Anzahl der Ergebnisse angeben, die durch die Filter aktualisiert wurden. Wir erledigen das mit JavaScript, da es über die Möglichkeiten von Zählern hinausgeht.
Verschachtelung
Der Zähleralgorithmus hat sich mit CSS-Nesting-1 gut angefühlt, da ich die gesamte Logik in einen Block packen konnte. Die Informationen sind mobil und zentralisiert, sodass sie leicht gelesen und aktualisiert werden können.
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
Layouts
In diesem Abschnitt werden die Layouts zwischen den beiden Komponenten beschrieben. Die meisten Layoutstile sind für die Desktop-Checkbox-Komponente.
Das Formular
Um die Lesbarkeit und Scanbarkeit für Nutzer zu optimieren, hat das Formular eine maximale Breite von 30 Zeichen. Dadurch wird im Grunde eine optische Zeilenbreite für jedes Filterlabel festgelegt. Im Formular wird das Rasterlayout und das Attribut gap
verwendet, um die Fieldsets zu verteilen.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
Das <select>
-Element
Die Liste mit Labels und die Kästchen nehmen auf Mobilgeräten zu viel Platz ein. Daher wird bei den Layoutprüfungen das primäre Zeigegerät des Nutzers berücksichtigt, um die Benutzeroberfläche für die Touchbedienung zu optimieren.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
Ein Wert von coarse
gibt an, dass der Nutzer mit seinem primären Eingabegerät nicht sehr präzise mit dem Bildschirm interagieren kann. Auf einem Mobilgerät ist der Zeigerwert oft coarse
, da die primäre Interaktion über Berührung erfolgt. Auf einem Desktop-Gerät ist der Zeigerwert oft fine
, da in der Regel eine Maus oder ein anderes hochpräzises Eingabegerät angeschlossen ist.
Die Fieldsets
Das Standarddesign und ‑layout eines <fieldset>
mit einem <legend>
ist einzigartig:
Normalerweise verwende ich die gap
-Eigenschaft, um die untergeordneten Elemente zu platzieren. Die einzigartige Positionierung des <legend>
-Elements macht es jedoch schwierig, eine gleichmäßig verteilte Gruppe von untergeordneten Elementen zu erstellen. Statt gap
werden der Selektor für das benachbarte Geschwisterelement und margin-block-start
verwendet.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Dadurch wird verhindert, dass der Abstand des <legend>
-Elements angepasst wird, da nur die untergeordneten <div>
-Elemente ausgerichtet werden.
Das Filterlabel und das Kästchen
Als direkt untergeordnetes Element von <fieldset>
und innerhalb der maximalen Breite des 30ch
des Formulars kann der Labeltext umgebrochen werden, wenn er zu lang ist. Das Umbrechen von Text ist zwar praktisch, aber es sollte nicht zu einer falschen Ausrichtung zwischen Text und Kontrollkästchen führen. Flexbox ist dafür ideal.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}

Das animierte Raster
Die Layout-Animation wird von Isotope ausgeführt. Ein leistungsstarkes und leistungsfähiges Plug-in für interaktives Sortieren und Filtern.
JavaScript
JavaScript hilft nicht nur dabei, ein ansprechendes animiertes, interaktives Raster zu erstellen, sondern wird auch verwendet, um einige Unregelmäßigkeiten zu beheben.
Normalisieren der Nutzereingabe
Dieses Design hat ein Formular mit zwei verschiedenen Möglichkeiten zur Eingabe, die nicht serialisiert werden. Mit etwas JavaScript können wir die Daten jedoch normalisieren.
Ich habe mich dafür entschieden, die Datenstruktur des Elements <select>
an die Struktur der gruppierten Checkboxen anzupassen. Dazu wird dem <select>
-Element ein input
-Ereignis-Listener hinzugefügt, woraufhin die selectedOptions
-Elemente zugeordnet werden.
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
}, [])
})
Jetzt können Sie das Formular einreichen oder, im Fall dieser Demo, Isotope anweisen, wonach gefiltert werden soll.
Statusrollelement fertigstellen
Das Element zählt und gibt die Anzahl der Filter nur basierend auf der Interaktion mit dem Kontrollkästchen an. Ich fand es jedoch eine gute Idee, zusätzlich die Anzahl der Ergebnisse anzugeben und dafür zu sorgen, dass auch die Auswahl des <select>
-Elements berücksichtigt wird.
Die Auswahl des <select>
-Elements wird im counter()
berücksichtigt.
Im Abschnitt zur Datennormalisierung wurde bereits ein Listener für die Eingabe erstellt. Am Ende dieser Funktion sind die Anzahl der ausgewählten Filter und die Anzahl der Ergebnisse für diese Filter bekannt. Die Werte können so an das Element „state role“ übergeben werden.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Im Element role="status"
angezeigte Ergebnisse
:checked
bietet eine integrierte Möglichkeit, die Anzahl der ausgewählten Filter an das Statusrollenelement zu übergeben, aber die gefilterte Anzahl der Ergebnisse ist nicht sichtbar.
JavaScript kann auf Interaktionen mit den Kästchen warten und nach dem Filtern des Rasters textContent
hinzufügen, so wie das <select>
-Element.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
Insgesamt wird mit dieser Arbeit die Ankündigung „2 Filter ergeben 25 Ergebnisse“ abgeschlossen.
Jetzt können alle Nutzer von unserer hervorragenden Erfahrung mit unterstützenden Technologien profitieren, unabhängig davon, wie sie mit ihnen interagieren.
Fazit
Jetzt wissen Sie, wie ich es gemacht habe. Wie würden Sie vorgehen? 🙂
Wir möchten unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, die das Web bietet. Erstelle eine Demo, schick mir einen Tweet mit den Links und ich füge sie unten im Bereich „Community-Remixe“ hinzu.
Community-Remixe
Noch keine Aktivität hierzu.