Ein grundlegender Überblick darüber, wie Sie eine responsive, adaptive und barrierefreie Komponente mit Mehrfachauswahl erstellen können, um Nutzerfreundlichkeit zu sortieren und zu filtern.
In diesem Beitrag möchte ich meine Gedanken zu einer Möglichkeit zur Erstellung einer Mehrfachauswahlkomponente teilen. Demo ansehen
Falls Sie Videos bevorzugen, finden Sie hier eine YouTube-Version dieses Beitrags:
Übersicht
Nutzern werden oft Elemente angezeigt, manchmal sehr viele. In diesen Fällen kann es sinnvoll sein, eine Möglichkeit zur Reduzierung der Liste anzubieten, um eine Überforderung durch zu viele Optionen zu vermeiden. In diesem Blogpost wird die Filteroberfläche als Möglichkeit zur Reduzierung der Auswahlmöglichkeiten untersucht. Dazu werden Artikelattribute angezeigt, die Nutzer auswählen oder deaktivieren können. So werden die Ergebnisse reduziert und die Auswahl überladen.
Interaktionen
Ziel ist es, allen Nutzern und ihren unterschiedlichen Eingabetypen eine schnelle Navigation durch die Filteroptionen zu ermöglichen. Dazu werden zwei anpassbare und responsive Komponenten verwendet. Eine traditionelle Seitenleiste mit Kästchen für Desktop-Computer, Tastaturen und Screenreader sowie ein <select
multiple>
für Touchbildschirme.
Die Entscheidung, die integrierte Mehrfachauswahl für Touchbedienung und nicht für Computer zu verwenden, spart Arbeit und schafft Arbeit, bietet aber meiner Meinung nach eine angemessene Benutzererfahrung mit weniger Code-Schulden als die Erstellung der gesamten responsiven Benutzeroberfläche in einer Komponente.
Berührung
Die Touch-Komponente spart Platz und trägt dazu bei, die Genauigkeit der Nutzerinteraktion auf Mobilgeräten zu verbessern. So wird Platz gespart, da eine ganze Seitenleiste mit Kästchen in ein integriertes<select>
Touch-Overlay minimiert wird. Sie trägt zur Eingabegenauigkeit bei, da das System ein großes Touch-Overlay anzeigt.
Tastatur und Gamepad
Unten sehen Sie eine Demonstration, wie Sie <select multiple>
über die Tastatur verwenden.
Diese integrierte Mehrfachauswahl kann nicht gestaltet werden und wird nur in einem kompakten Layout angeboten, das nicht für die Darstellung vieler Optionen geeignet ist. Sehen Sie nur, dass Sie die Bandbreite der Optionen in diesem winzigen Feld nicht sehen? Sie können die Größe zwar ändern, aber sie ist immer noch nicht so nutzerfreundlich wie eine Seitenleiste mit Kästchen.
Markieren & Zeichnen
Beide Komponenten befinden sich im selben <form>
-Element. Die Ergebnisse dieses Formulars, ob Kästchen oder Mehrfachauswahl, 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 auf diese Weise strukturiert ist, erkennen Screenreader und FormData automatisch die Beziehung der Elemente.
<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 meine in einen <div>
-Block eingeschlossen, damit die CSS-Eigenschaft gap
sie gleichmäßig platzieren und die Ausrichtung beibehalten kann, wenn Labels mehrzeilig sind.
<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. Es ist, als würden Sie die Interaktion
von einer Radio- zu einer Kontrollkästchen-Liste ändern.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Wenn du innerhalb eines <select>
-Elements Gruppen labeln und erstellen möchtest, verwende das Element <optgroup>
und gib ihm ein label
-Attribut und einen label
-Wert. Dieses Element und dieses Attribut ä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>
Eingaben mit Zählern erfassen, um assistive Technologien zu informieren
Bei dieser Nutzererfahrung wird die Statusrolle verwendet, um die Anzahl der Filter für Screenreader und andere Hilfstechnologien zu erfassen und zu verwalten. In diesem YouTube-Video wird die Funktion veranschaulicht. 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 in einem übergeordneten Element der Eingaben und des Statuselements erstellen.
aside {
counter-reset: filters;
}
Die Anzahl ist standardmäßig 0
, was sehr gut ist. Standardmäßig ist in diesem Design nichts :checked
.
Als Nächstes richten wir das Ziel auf untergeordnete Elemente des Elements <aside>
aus, die :checked
sind, um den neu erstellten Zähler zu erhöhen. Wenn der Nutzer den Status der Eingaben ändert, wird der filters
-Zähler erhöht.
aside :checked {
counter-increment: filters;
}
CSS kennt jetzt die allgemeine Gesamtzahl der Kästchen-UI und das Status-Rollenelement ist leer und wartet auf Werte. Da die Zählung in CSS im Arbeitsspeicher gespeichert wird, können Sie mit der Funktion counter()
auf den Wert aus dem Inhalt des Pseudoelements zugreifen:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Im HTML-Code für das Statusrollenelement wird jetzt einem Screenreader „2 Filter“ mitgeteilt. Das ist ein guter Anfang, aber wir können noch besser werden. Zum Beispiel könnten wir die Anzahl der Ergebnisse anzeigen, die durch die Filter aktualisiert wurden. Wir führen diese Arbeit in JavaScript aus, da Zähler dafür nicht geeignet sind.
Nesting-Aufregung
Der Zähleralgorithmus funktionierte mit CSS-Verschachtelung 1 hervorragend, da ich die gesamte Logik in einen Block einfügen konnte. Sie ist portabel und zentralisiert für das Lesen und Aktualisieren.
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 Kästchenkomponente auf dem Computer gedacht.
Das Formular
Um die Lesbarkeit und Übersichtlichkeit für Nutzer zu optimieren, hat das Formular eine maximale Breite von 30 Zeichen. Damit wird im Grunde eine optische Zeilenbreite für jedes Filterlabel festgelegt. Im Formular wird das Rasterlayout und das Attribut gap
verwendet, um die Feldgruppen zu verteilen.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
Das <select>
-Element
Die Liste der Labels und Kästchen belegen auf Mobilgeräten zu viel Platz. Daher wird im Layout das primäre Eingabegerät des Nutzers geprüft, um die Oberfläche für Touchbedienung anzupassen.
@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 Display interagieren kann. Auf einem Mobilgerät ist der Zeigerwert oft coarse
, da die primäre Interaktion das Tippen ist. Auf einem Desktop-Gerät ist der Cursorwert häufig fine
, da in der Regel eine Maus oder ein anderes Eingabegerät mit hoher Präzision angeschlossen ist.
Die fieldsets
Der Standardstil und das Standardlayout einer <fieldset>
mit einem <legend>
sind eindeutig:
Normalerweise verwende ich die Eigenschaft gap
, um die Abstände zwischen meinen untergeordneten Elementen zu steuern. Aufgrund der einzigartigen Positionierung des <legend>
ist es jedoch schwierig, eine gleichmäßig verteilte Gruppe von untergeordneten Elementen zu erstellen. Anstelle von gap
werden die adjacent sibling-Auswahl und margin-block-start
verwendet.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Dadurch wird verhindert, dass der Bereich für <legend>
angepasst wird, da nur die untergeordneten Elemente <div>
ausgerichtet werden.
Filterlabel und Kästchen
Da es sich um ein direkt untergeordnetes Element eines <fieldset>
handelt und die maximale Breite des 30ch
des Formulars nicht überschritten wird, wird der Labeltext möglicherweise umgebrochen, wenn er zu lang ist. Textumbruch ist in Ordnung, aber eine Fehlausrichtung zwischen Text und Kästchen ist nicht in Ordnung. Flexbox eignet sich dafür hervorragend.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
Das animierte Raster
Die Layoutanimation wird von Isotope erstellt. Ein leistungsstarkes Plug-in für die interaktive Sortierung und Filterung.
JavaScript
JavaScript wird nicht nur verwendet, um ein ansprechendes animiertes, interaktives Raster zu erstellen, sondern auch, um einige Ecken und Kanten zu glätten.
Normalisierung der Nutzereingabe
Dieses Design hat ein Formular mit zwei verschiedenen Eingabemöglichkeiten, die nicht serialisiert werden. Mit etwas JavaScript können wir die Daten jedoch normalisieren.
Ich habe die Datenstruktur des <select>
-Elements an die Struktur der gruppierten Kästchen angepasst. Dazu wird dem <select>
-Element ein input
-Ereignis-Listener hinzugefügt, wodurch selectedOptions
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 absenden oder in diesem Fall Isotope anweisen, nach welchen Kriterien gefiltert werden soll.
Statusrollenelement fertigstellen
Das Element zählt und anzeigt nur die Filteranzahl basierend auf der Kästcheninteraktion. Ich fand es jedoch sinnvoll, zusätzlich die Anzahl der Ergebnisse anzugeben und dafür zu sorgen, dass auch die Auswahlmöglichkeiten des <select>
-Elements gezählt werden.
<select>
Elementauswahl wird in counter()
widergespiegelt
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 Rollenelement des Bundesstaats übergeben werden.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Ergebnisse, die im Element role="status"
berücksichtigt werden
:checked
bietet eine integrierte Möglichkeit, die Anzahl der ausgewählten Filter an das Status-Rollenelement weiterzugeben. Die gefilterte Anzahl der Ergebnisse ist jedoch nicht sichtbar.
JavaScript kann die Interaktion mit den Kästchen überwachen und nach dem Filtern des Rasters textContent
wie das <select>
-Element hinzufügen.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
Zusammengenommen vervollständigt diese Arbeit die Ankündigung „2 Filter mit 25 Ergebnissen“.
Jetzt können alle Nutzer unsere hervorragenden Hilfstechnologien nutzen, unabhängig davon, wie sie damit interagieren.
Fazit
Wie würden Sie es machen?
Lassen Sie uns unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, wie Sie im Web entwickeln können. Erstelle eine Demo, tweete mir Links und ich füge sie unten in den Abschnitt „Community-Remixe“ hinzu.
Remixe der Community
Noch keine Aktivität hierzu.