Vorschlags-Suche
Viele Online-Shops haben eine zentrale Suche – was ja auch logisch erscheint, denn um Produkte oder Dienstleistungen auffinden zu können, braucht es eine potente Finde-Funktion.
Die meisten E-Commerce-Projekte arbeiten aber nicht mit einem einfachen Suchfeld, das seine Macht erst dann zeigt, wenn man auf eine Absende-Schaltfläche klickt. Vielmehr haben sich in Onlineshops übliche Suchfelder ihre Scheibe von Google.de abgeschnitten: Während die nutzende Person noch tippt, werden schon einige Vorschläge basierend auf der aktuellen Eingabe gemacht.
In diesem Modul soll es darum gehen, diese häufig „Combobox“ genannte Funktion auf eine zugängliche Art und Weise zu implementieren – also ein Eingabefeld mit auf das Eingetippte „reagierender“ Vorschlagsliste - und dabei vor allem Screenreader- und Tastaturnutzende zu bedenken.
Bevor man sich mit komplexen ARIA-Konstruktionen beschäftigt, sollte der erste Impuls immer die Frage sein: „Kann man das gewünschte Widget mit HTML-Mitteln abbilden?“. Die Antwort hierauf ist leider „eher nein“: Es gibt zwar mit dem <datalist>-Element (das mit einem Eingabefeld wie z. B. <input type="text /> assoziiert ist) ein Element, was Vorschläge aufgrund von Textfeld-Eingaben liefert, aber <input> und <datalist> haben allgemeine und situationsspezifische Nachteile:
- HTML-Elemente sind sonst in über 90% der Fälle „von Haus aus barrierefrei“ –
<datalist>aber ausgerechnet nicht. Denn die Vorschläge reagieren nicht, wenn die Schriftgröße des kompletten Dokuments z. B. durch Zoomen vergrößert wird. Außerdem ist die Tastaturbedienung in der Vorschlagsliste eingeschränkt, wenn es mehr "Suggestionen" gibt, als gerade in den Viewport passen. Zudem gibt es im Hochkontrastmodus von Windows Probleme mit der Fokushervorhebung. - Man kann die einzelnen Vorschläge nicht gestalten. Ähnlich übrigens wie bei Optionen eines
<select>-Elements haben wir es hier mit nicht-beeinflussbaren Teilen des Nutzerinterfaces bzw. mit Betriebbsystem-Oberflächen zu tun. - Selbst wenn die ersten beiden Nachteile (oder „Show-Stopper“) nicht existieren würden, könnte man mit dem
<datalist>-Element nicht die Konstruktionen bauen, die man in E-Commerce-Autocompletes findet: Zum Beispiel das Suchen in mehreren Inhaltsarten (z. B. Produkte und statische Seiten) oder Vorschaubilder und Preise in der Vorschlagsliste.
Das führt uns also dazu, in den ARIA-Werkzeugkasten nach geeigneten Instrumenten zu schauen (und sich an den Respekt vor ARIA und allem, was dazu gehört zu erinnern, denn: die Muster im „ARIA Authoring Practices Guide“ sind eher akademisch, eher mit dem Gedanken “so sollte es in einer perfekten Welt sein“ gebaut – nicht alle der dort zu findenden Patterns sind gut unterstützt oder funktionieren auch mobil). Und man wird tatsächlich fündig, in Form des so genannten Combobox-Musters. Von diesem gibt es einige Unterarten und was Online-Shop-Autocompletes vermutlich am nächsten kommt, ist "Editable Combobox With Both List and Inline Autocomplete Example" – also ein bearbeitbares Feld mit Vorschlagsliste und Autocomplete.
Funktionell bietet dieses Pattern schon einiges, z. B. das Reagieren auf Tastatureingaben und ein Vorschlag-Zusammenfiltern in Echtzeit. Zusätzlich sind auch Eingabefeld und Vorschlagsliste programmatisch miteinander assoziiert und kommunizieren den aktuell ausgewählten Vorschlag auch nicht-visuell an Nutzende von Screenreadern. Oben drauf ist eine für solche Comboboxen charakteristische Tastaturbedienung mit Pfeiltasten implementiert.
Leider ist das Muster aus den „ARIA Practices Guides“ zwar ein Schritt in die richtige Richtung, aber immer noch nicht die fertige Lösung, die wir für den Bau einer solchen „E-Commerce-Combobox“ benötigen. Fassen wir deswegen kurz unsere beispielhaften Anforderungen an ein solches Muster zusammen:
- Es sollte ermöglichen, mit nur einer (Teil-)Eingabe in mehreren Inhaltsgruppen (Datenpools) zu suchen.
- Wenn eine dieser Gruppen Produkte sind (was in einem E-Commerce-Kontext dann doch sehr wahrscheinlich ist), sollten Preise und Vorschaubilder ausgegeben werden können.
- Falls die Eingabe in das Suchfeld keine Vorschläge (in keinen der Pools) erzeugt, soll es wie ein klassisches Suchformular funktionieren, also das Eingegebene per z. B. Post-Request an eine Suchfunktion schicken und auf einer Suchergebnisseite ausgeben.
Ich habe hierzu ein wenig nach Best Practices recherchiert aber an den üblichen Stellen (ARIA Practices Guides, öffentliche Komponentenbibliotheken von Regierungen, Publikationen von Fachkolleg*innen) allerdings nichts passendes gefunden. Auf ein interessantes Widget bin ich allerdings beim US-amerikanischen Shop-Anbieter Shopify gestoßen. E-Commerce-Projekte unterliegen in den Vereinigten Staaten diversen Anti-Diskrimininierungs-Gesetzen und schreiben unter anderem ihre Zugänglichkeit vor. Entsprechend sinnvoll ist es für das Unternehmen, mindestens ein so genanntes Shop-Frontend anzubieten, dass als „barrierefrei“ gelten kann. Dieses sogenannte „Theme“ heißt „dawn“ und wartet mit unter anderem einer spannenden und zugänglichen Combobox auf. Barrierefreiheitsfachkräfte intern bei Shopify und extern beim Abieter Fable (ein Fachunternehmen für das Usability Testing von digitalen Projekten von Menschen mit Behinderungen) haben gemeinsam ein E-Commerce-Combobox-Muster entwickelt und getestet, das ich im Folgenden gerne vorstellen will. Und auch wenn das Pattern nicht Teil der ARIA Practice Guides ist, so hat zumindest der – übrigens selbst Screenreader-nutzende - Vorsitzende der APG-Arbeitsgruppe lobende Worte für den Ansatz. Halten wir fest: Ein definitives und „normatives“ How To für E-Commerce-Comboboxes gibt es (noch?) nicht, sehr wohl aber ein Best Practices. Und wie man dieses zugegebenermaßen komplizierte Konstrukt genau baut, ist Gegenstand der nächsten Abschnitte:
HTML-Stuktur und Rollen
Beginnen wir mit den nötigen Rollen: Zunächst setzen wir die Rolle eines Standard-Texteingabefeldes auf combobox und kommunizieren damit, dass es sich um kein übliches Texteingabefeld handelt – sondern um eines, dass zusätzlich Vorschläge, passend zu der aktuellen Eingabe, produziert.
Im Dokument direkt auf dieses Eingabefeld folgen muss nun ein Container, z. B. ein <div>, dem explizit die Rolle listbox gegeben werden muss. Dies ist der Container, der alle Vorschläge beherbergen wird. Hier wird klar, dass Comboboxen strukturell mit <select>-Elementen, also Einfachauswahlfeldern verwandt sind. Die listbox benötigt zusätzlich noch eine ID, die wir später in den ARIA-Eigenschaften (nächster Abschnitt) brauchen werden.
<input role="combobox" />
<div role="listbox" id="listbox">
</div>
Innerhalb dieser „Listbox“ werden dann die einzelnen Vorschläge – z. B. zur Sucheingabe passende Produkte oder Seiten – je mit der Rolle option versehen. Gibt es mehrere „Vorschlags-Pools“ werden diese Optionen in Gruppen zusammengefasst, das passiert mit role="group". Auch wenn wir die semantischen Rollen per ausdrücklichem role-Attribut überschreiben und die ursprüngliche Semantik entsprechend verloren geht, lohnt es sich meiner Meinung nach mindestens für das Verständnis des Codes, Gruppen und einzelne Vorschläge in Listenform zu gießen. Auch einzelne Vorschläge oder Optionen brauchen je eine ID, auch hier wird in der nächsten Sektion klarer, warum:
<input role="combobox" />
<div role="listbox" id="listbox">
<ul role="group">
<li role="option" id="option1">Vorschlag 1</li>
<li role="option" id="option2">Vorschlag 1</li>
</ul>
<ul role="group">
<li role="option" id="option3">Vorschlag 3</li>
<li role="option" id="option4">Vorschlag 4</li>
</ul>
</div>
Wenn man der ARIA-Spezifikation für die Rolle listbox folgt, erkennt man, dass die zulässigen Kindelemente für Listboxes nur option und group (also Gruppen einzelner options) sind. „Zulässige Kindelemente“ bedeutet hier, dass nur diese Rollen an Screenreader-Nutzende kommuniziert werden und etwaige andere vorhandene Rollen ignoriert werden. Praktisch heißt das, dass wir andere Elemente (mit abweichenden Rollen) in unserer Vorschlags-Box platzieren können, aber fest damit rechnen müssen, dass diese in einem Bildschirmvorleseprogramm nicht ausgegeben werden. Da wir nun vorhaben, dass Nutzende mit einem Klick auf einen z. B. Produktvorschlag direkt zur Produkteinzelseite kommen sollen, platzieren wir einen Link innerhalb unseres Einzelvorschlags (behalten aber im Hinterkopf, dass diese Link-Semantik in Screenreadern „verlorengeht“):
<!-- ... -->
<li role="option" id="option4">
<a href="/produkt/option4">Vorschlag 4</a>
</li>
<!-- ... -->
Um den einzelnen „Pools“ einen zugänglichen Namen zu geben, nutzen wir visuell wahrnehmbare, dort aber „eigentlich verbotene“ Überschriften, deren Textinhalt wir aber dennoch per Referenzierung als Gruppen-Beschriftung nutzen können. Per aria-labelledby, das auf die ID der Überschrift zeigt, und angewendet die Optionsgruppe geben wir ihr einen so genannten zugänglichen Namen:
<!-- ... -->
<h2 id="name-produkt-gruppe">Produkte</h2>
<ul role="group" aria-labelledby="name-produkt-gruppe">
<li role="option" id="option1">Vorschlag 1</li>
<li role="option" id="option2">Vorschlag 1</li>
</ul>
<!-- ... -->
Und wo wir gerade dabei sind: wenn es in einem einzelnen option-Vorschlag ein Bild gibt, wird das für Screenreader-Nutzende leider auch nicht ausgegeben – wir sollten dennoch Abbildungen in den Vorschlägen platzieren, wenn es im Design so angelegt ist.
Ein kleiner Exkurs: Dass nun in einem Screenreader die Aktivierung einer Option nun häufig zu einem so genannten Kontextwechsel (Aufruf einer neuen Seite) führt, könnte WCAG-Kundigen wie ein Verstoß von Erfolgskriterium 3.2.2 vorkommen („Keine unerwartete Kontextänderung bei Eingabe“). Allerdings kann man hier sehr gut argumentieren, dass dieser Kontextwechsel im Zusammenhang einer typischen E-Commerce-Combobox durchaus erwartbar ist, und dieser Einschätzung stimmen viele Fachkolleg*innen zu.
Im nächsten Abschnitt geht es weiter und wir betrachten ARIA-Attribute, von denen einige statisch sind und Verwandtschaften zwischen Elementen erläutern. Richtig spannend wird es aber, wenn wir unseren Fokus (Wortspiel gewollt) auf dynamische ARIA-Werte setzen.
ARIA Properties
Kommen wir nun zu den ARIA-Attributen, die auf der Combobox, der Listbox und einzelnen Optionen (Vorschlägen) existieren müssen.
Statische ARIA-Eigenschaften
aria-autocomplete="list" auf der Combobox
Mit aria-autocomplete="list" kommunizieren wir an Screenreader-Nutzende, dass diese Combobox von der Texteingabe abhängige Vorschläge anzeigen kann. Andere denkbare Werte wären none (das wäre eine Combobox ohne eine Vorschläge nach Eingabe), inline (ein klassisches Inline-Autocomplete) und both (das wäre entsprechend beides kombiniert).
aria-controls auf der Combobox
Dieses Attribut baut eine programmatische Brücke zwischen zwei Elementen und kommuniziert, dass Veränderungen im einen auch häufig mehrere Veränderungen im anderen auslösen wird. Hier bestimmt die Eingabe im Textfeld die Vorschlagsliste, beziehungsweise: welche Optionen dort zu sehen sein werden. Entsprechend nimmt aria-controls als Wert die ID unserer Listbox entgegen.
Dynamische ARIA-Eigenschaften
aria-expanded auf der Combobox
Wie beim Ausklapp-ARIA-Muster (siehe Basics-Modul) auch ist dieses Attribut erstens auf dem Ausklapp-Auslöser (hier: der Combobox) platziert, kommuniziert zweitens den Zustand des beeinflussten Containers (hier: der Listbox) und muss somit drittens dynamische Werte haben. Ein true bedeutet "wahrnehmbar", sichtbar und ein false entsprechend ungefähr so viel wie „es gibt etwas, das sich ausklappen lässt, es ist aktuell aber versteckt“.
aria-selected auf den Optionen/Vorschlägen
Wenn man per Screenreader oder Tastatur durch die Vorschlagsliste navigiert (wie das genau geht: siehe nächster Abschnitt), erhalten einzelne options das Attribut aria-selected="true". Nicht ausgewählte Vorschläge sind entsprechend aria-selected="false".
aria-activedecendant auf der Combobox
Das Attribut aria-activedecendant ist eine dynamisch zu füllende Eigenschaft, das auf der Combobox zugeordnet wird. Wie bei aria-controls ist der Attributwert eine ID, und zwar jene des aktuell ausgewählten Vorschlags (anders gesagt: der option, die gerade aria-selected="true" ist, was auch die frühere ID-Vergabe auf einzelnen options erklärt). In einem Live-Dokument könnte das folgendermaßen aussehen:
<input role="combobox" aria-controls="the-listbox" aria-activedescendant="option2" aria-expanded="true" />
<div role="listbox" id="the-listbox" >
<ul role="group">
<li role="option" id="option1" aria-selected="false">Vorschlag 1</li>
<li role="option" id="option2" aria-selected="true">Vorschlag 1</li>
</ul>
<ul role="group">
<li role="option" id="option3" aria-selected="false">Vorschlag 3</li>
<li role="option" id="option4" aria-selected="false">Vorschlag 4</li>
</ul>
</div>
Wie und mit welchen Tastaturanschlägen man einen Vorschlag aus der Listbox auswählt und damit den Wert von aria-activedecendant indirekt ändert, ist Gegenstand des nächsten Abschnitts.
Tastaturverhalten
Eine Besonderheit bei der Combobox ist, dass wir dort von zwei Arten des Fokus-Setzens reden:
- 1. Der altbekannten Art – man nutzt z. B. die Tabulatortaste auf der Tastatur, um diesen Fokus „der alten Schule“ zu versetzen. Man kann übrigens mit
document.activeElementin der JavaScript-Konsole herausfinden, welches Element gerade „klassischen Fokus“ hat. - 2. Einer Art „Pseudofokus“. Dieser ist nicht per Tabulatortaste zu ändern, nicht so elegant zu debuggen wie der klassische Fokus und tritt im Zusammenhang mit Elementen auf, die
aria-activedescendantbesitzen.
Unsere E-Commerce-Combobox vereint beide Fokusarten – der echte Fokus verbleibt auf dem Eingabefeld, während man den Pseudofokus per Pfeiltasten innerhalb der Vorschlagsliste/Listbox versetzen kann (das logischerweise nur, wenn es Vorschläge gibt und die Listbox aktuell wahrnehmbar ist). Dass der echte Fokus auf dem Eingabefeld bleibt, ergibt sehr viel Sinn, denn schließlich will es Eingaben entgegennehmen und muss auf heruntergedrückte Buchstaben-Tasten reagieren, die ja wiederum Teile eines – beispielweise – gesuchten Produktnamens bilden können. Finden sich nun Vorschläge oder options zur Eingabe, erscheint die Listbox und der oder die Nutzende kann innerhalb der Vorschlagsliste mit den Pfeiltasten Hoch und Runter navigieren. Ist gerade ein Vorschlag „im Pseudofokus“ und die Eingabetaste wird gedrückt, so wird der Vorschlag aktiviert – das könnte zum Beispiel bedeuten, dass einem Link in der option gefolgt wird und z. B. eine Produkteinzelseite aufgerufen wird. Oder aber die Combobox fungiert als normales Eingabefeld in einem Formular funktioniert und dieses schlicht und einfach abgesendet wird.
Daraus ergeben sich ein paar Aufgaben in der Programmierung der E-Commerce-Combobox:
- Man muss Tastatureingaben im Eingabefeld überwachen, normale Anschläge von so genannten druckbaren Zeichen (A-Z, 0-9, ß, Umlaute usw.) durchlassen - denn diese könnten ja z. B. auf ein Produkt passen und möglicherweise das Erscheinen von passemdem Vorschlägen auslösen.
- Entdeckt man allerdings Tastaturanschläge der vertikalen Pfeiltasten
HochundRunter, führt das dazu, dass der Pseudofokus innerhalb der Vorschlagsliste versetzt werden muss. Programmatisch bedeutet das weiterhin, dass eineoption, die gerade im Pseudofokus ist, das Attributaria-selected="true"erhalten muss. Undaria-activedescendantauf dem Eingabefeld muss dynamisch auf den Wert der ID der Option im Pseudofokus geändert werden. Übrigens: Wenn man Text in das Eingabefeld eingibt (die bereits erwähnten "druckbaren Zeichen"), solltearia-activedescendantgeleert oder entfernt werden. - Gleichzeitig braucht auch der Pseudofokus natürlich einen ausreichend wahrnehmbaren Fokusindikator (unter Beachtung von Vorgaben zu Textkontrasten, Nicht-Text-Kontrasten und Benutzung von Farbe. Weil wir hier nicht von einem klassischen Fokus sprechen, wäre
:focusim CSS keine Option (denn der echte ist ja auf der Combobox). Aber ein CSS-Attributselektor wieoption[aria-selected="true"]zum Gestalten des Pseudofokus-Indikators ergibt hier alternativ sehr viel Sinn. - Abschließend braucht man noch ein spezielles Handling der Tastatureingaben
EnterundEscape. Während das erste die aktuell ausgewählte Option übernimmt oder aufruft – bleiben wir abstrakt und sagen „aktiviert“ – führt ein Tastendruck des letzten dazu, dass sich die Vorschlagsliste wieder schließt. - Ist man beim Versetzen des Pseudofokus nun entweder am unteren oder oberen Ende der Vorschlagsliste angelangt, so muss ein weiterer Anschlag der horizontalen Pfeiltasten (also
Pfeil runter,Pfeil hoch) dazu führen, dass man jeweils zum anderen Ende der Vorschlaäge gelangt. Beispiel: hat man zum letzten Vorschlag einer Vorschlagsliste navigiert und drückt dannPfeil runter, so sollte man auf dem ersten Vorschlag der Liste landen. - Es gibt noch weitere Vorgaben in Kombination von
Pfeil runterund derHochstelltaste/Shift: Dieser Shortcut soll, wenn das Eingabefeld im echten Fokus ist, die Vorschlagsliste wahrnehmbar machen (öffnen), allerdings ohne dabei den Pseudofokus zu versetzen.
Kurz zusammengefasst: Im letzten Abschnitt haben wir unter anderem aria-activedescendant kennengelernt und in diesem, dass das Attribut eine Art Indikator ist, auf welchem Element ein so genannter Pseudofokus liegt. Dazu muss aria-activedescendant die ID des Elements im Pseudofokus entgegen nehmen und die Wert-Befüllung dynamisch von Statten gehen. Ein Versetzen des Pseudofokus gelingt Nutzenden per den vertikalen Pfeiltasten Pfeil hoch und Pfeil runter.
Beispiel auf ecbf.shop
Auf ecbf.shop habe ich eine typische E-Commerce-Combobox implementiert, die von der Shopify-Combobox namens „predictive search“ inspiriert wurde (kopiert habe ich den Code entsprechend der Lizenzbedingungen des dawn-Themes natürlich nicht). Diese Combobox nutzt die bisher erklärten Strukturen, Eigenschaften und Verhaltensweisen dieses Best Practices und ist in Form einer Web Component namens ecbf-combobox-search umgesetzt. Wenn man die Vorschlags-Suche ausprobieren möchte, lohnt es sich, die Zeichenfolge „an“ einzugeben, denn in dem Fall werden sich einerseits Produkt- und andererseits Seiten-Vorschläge finden lassen (jeweils in der entsprechenden Gruppe).
In einem wichtigen Aspekt unterscheidet sich meine Komponente allerdings von Beispielen aus dem echten Leben: Die eigentliche Suchlogik ist bewusst unterkomplex gehalten - schließlich wollte ich in diesem Modul das Prinzip einer zugänglichen E-Commerce-Combobox erklären und nicht die programmatische Logik von Suchfunktionen wie solr. Das überlasse ich Profis in diesem Bereich und freue mich über realistischere Anpassungen der dafür zentralem Komponenten-Methode getSearchResults() für das echte Leben.
Ein letzter Satz noch zu aria-activedescendant: Bis vor Kurzem wurde das Attribut in Apples Voice Over auf dem Mac nicht unterstützt. Aber angeblich scheint sich das mit Safari 18 geändert zu haben. Bis das verifiziert ist und intensiv getestet wurde, VoiceOver (Mac) endlich zu den anderen Screenreadern wie JAWS, NVDA oder selbst seiner eigenen iOS-Variante aufschließt, kann man sich vielleicht am Prinzip der "Graceful Degradation" trösten und sich erinnern, dass eine Combobox in ihrem Kern ein Eingabefeld ist – und dieses kann als normales Textfeld in einem normalen Formular mit normaler Suchfunktion per zum Beispiel GET-Request funktionieren. Weniger komfortabel, aber durch seine Einfachheit definitiv barrierefrei.
Übungen
Zusammenfassung
- Die Produktsuche ist ein wichtiges Instrument bei der Auffindbarkeit von Produkten und Dienstleistungen in einem Web-Shop
- Häufig arbeiten diese Produktsuchen mit Vorschlagslisten, die bei der Eingabe von Zeichenketten in einem Suchfeld unterhalb erscheinen. Dieses Muster aus Eingabefeld und Vorschlagsliste wird häufig „Combobox“ genannt.
- In diesem Modul wird ein zugängliches Combobox-Muster vorgestellt, das einerseits den Best Practices folgt, andererseits typische E-Commerce-Aspekte befolgt (beispielsweise führt eine Aktivierung eines Vorschlags aus der Liste zu einer Produkteinzelseite).
- Die wichtige Tastaturbedienung und Screenreaderkompatibilität dieser „E-Commerce-Combobox“ wird im Modul beschrieben und eine Komponente zur freien Nutzung angeboten.