Formulare/Suchen und Filtern
Dieses Tutorial soll einige Wege aufzeigen und dabei den Unterschied zwischen dem Durchsuchen von Inhalten einerseits und dem Filtern von Suchvorschlägen andererseits herausstellen.
Inhaltsverzeichnis
Vorüberlegungen
Eine Suche innerhalb der aktuellen Seite ist in jedem Browser über das Menü oder mit STRG F möglich. Diese Tastenkombination ist vielen Nutzern bereits aus Textverarbeitungen wie MS Word bekannt[1] und Sie sollten unbedingt darauf verzichten, diese Funktion nachzuprogrammieren.
Eine Suche innerhalb einer Website mit mehreren Unterseiten ist entweder bereits in vielen CMS integriert oder muss serverseitig erfolgen. Alternativ kann man auf externe Suchmaschinen zurückgreifen, was Nutzer aber aus dem eigenen Webauftritt wegführt.
<form role="search" method="GET" action="https://duckduckgo.com/">
<input name="q" type="search" aria-label="Suche auf selfhtml.org"/>
<input name="site" type="hidden" value="selfhtml.org"/>
<button>Suchen</button>
</form>
Duckduckgo erwartet für seine Suchfunktion bestimmte URL Parameter. Das Suchformular erreicht das, indem die Methode GET
eingestellt wird und die Eingabefelder passend benannt werden.
- q
- Der Begriff oder die Begriffe, wonach Duckduckgo suchen soll. Dies ist ein offenes Eingabefeld mit
type="search"
. - site
- Der Name der Domain, innerhalb der gesucht werden soll. Für eine site-spezifische Suche soll dieser Name nicht vom Benutzer eingegeben werden und muss auch nicht sichtbar sein, darum ist dieses Feld als
type="hidden"
angegeben.
Externe Suchmaschinen können natürlich immer nur das indexieren und durchsuchen, was auf Ihren HTML Seiten öffentlich zugänglich ist. Wenn Sie einen login-geschützten Bereich haben, sind Sie darauf angewiesen, eine eigene Suche zu programmieren. Das geschieht dann aber nicht mit JavaScript im Browser, sondern auf Ihrem Server und ist nicht Gegenstand dieses Artikels.
gefilterte Suche mit JavaScript
Auf umfangreichen Seiten mit vielen Informationen ist es eine gute Idee, den Benutzern eine Möglichkeit zu geben, die Informationsmenge an Hand von bestimmten Kriterien zu reduzieren oder zumindest die gewünschten Funktionen deutlich hervorzuheben.
Die im Browser integrierte Suchfunktion kann nach Wörtern suchen und diese hervorheben. Eine Suche dieser Art müssen wir deshalb nicht selbst bauen. Es ist auch ziemlich komplex, in einem mit HTML gespickten Text einen Suchbegriff hervorzuheben, wenn der Text dieses Begriffs durch HTML Markup unterbrochen ist. Für den Selbstbau geeignet ist dagegen ist eine Suchfunktion, die auf der Ebene von HTML Elementen relevante Informationseinheiten hervorhebt, oder weniger relevante Bereiche ausblendet.[2]
Das Script wird …
- beobachten, was ein Benutzer in die Sucheingabe eingibt,
- den innerText der durchsuchbaren Elemente filtern,
- testen, ob der Text den Suchbegriff enthält (.includes() ist hier das A und O!), und
- die Sichtbarkeit der (übergeordneten) Elemente umzuschalten, je nachdem, ob sie den Suchbegriff enthalten oder nicht
Information: Suche vs Filter
Die Begriffe „Suchen“ und „Filtern“ haben eine unterschiedliche Bedeutung, werden aber im Sprachgebrauch nicht immer klar unterschieden.
- Eine Suche beginnt bei Null und trägt aus einer (größeren) Datenquelle die Einträge zusammen, die auf die genannten Suchbedingungen zutreffen. Je nach gewählter Suchfunktion können auch Einträge gefunden werden, auf die nur ein Teil der Bedingungen zutrifft. Möglicherweise wird die Ergebnismenge auch noch nach Relevanz oder Alter sortiert. In unserem Beispiel setzen wir voraus, dass eine Suche (z.B. nach Vogelpark, bereits stattgefunden hat)
- Beim Filtern liegt die Ergebnismenge bereits vor, und das Ziel besteht darin, sie zu verkleinern. Die Filterkriterien können positiv (zeige nur X) oder negativ (zeige alles außer X) formuliert sein. Da ein Filter dazu dient, beim Finden zu helfen, wird er umgangssprachlich oft als „Suche“ bezeichnet.
- Es ist sehr oft so, dass Suchen und Filtern gemeinsam verwendet werden. Zunächst wird gesucht, und die Treffer dann durch Filtern verfeinert.[3]
Suchformular
Der Inhalt unserer Webseite besteht aus mehreren article-Elementen, die die Adresse und ein Beispielfoto enthalten:
<article id="de10319">
<h2>Tierpark Berlin</h2>
<p>
<img src="Sagittarius_serpentarius.jpg" alt="Sekretärvogel im Tierpark Belrin">
Am Tierpark 125
10319 Berlin</p>
</article>
<article id="de10787">
<h2>Zoologischer Garten Berlin AG</h2>
<p>
<img src="Glaucidium_perlatum_Berlin_Zoo.jpg" alt="Eule im Zoologischen Garten in Berlin">
Hardenbergplatz 8
10787 Berlin
<br>
<img src="Flamingo_Winter_Zoologischer_Garten_Berlin_cropped.jpg" alt="Flamingos im Winter"></p>
</article>
...
Eine in der Seite integrierte Filterfunktion benötigt JavaScript und kann daher nur ein progressive enhancement sein. Die Benutzeroberfläche für die Filterung sollte daher standardmäßig ausgeblendet sein und nur sichtbar werden, wenn JavaScript ausgeführt wird. Ein <form>
-Element ist nicht nötig, aber ein <search>
-Element bietet sich als Container für das Eingabefeld an.
<search id="filter">
<label for="suchbegriff">Zeige nur Ergebnisse mit </label>
<input type="search" id="suchbegriff">
</search>
Das Suchformular besteht aus einem Input type="search"-Feld, dass durch ein label-Element passend beschriftet ist.
Javascript
die Basis-Version
Die eigentliche Suche wird von der Funktion liveSearch() übernommen:
function liveSearch() {
let main = document.querySelector("main");
let alle_artikel = main.querySelectorAll('article');
let filterbegriff = document.querySelector('#filter input').value.toLocaleLowerCase();
if (filterbegriff.trim() == "") {
main.classList.remove("is-filtered");
}
else {
main.classList.add("is-filtered");
// Die Artikel auf der Seite durchlaufen.
for (let artikel of alle_artikel) {
// Wenn der Suchbegriff als (sichtbarer) Text auftaucht, den Artikel als Treffer markieren
let relevant = artikel.innerText.toLocaleLowerCase().includes(filterbegriff);
artikel.classList.toggle('is-relevant', relevant);
}
}
}
Die Funktion ermittelt mit querySelectorAll alle <article>
-Elemente im <main>
-Bereich. Das Ergebnis steht als eine statische NodeList zur Verfügung. Seitdem man auf den Internet Explorer keine Rücksicht mehr nehmen muss, können NodeList-Objekte mit einer for...of-Schleife einfach durchlaufen werden.
Der Filterbegriff wird aus dem Suchfeld (ein input-Element im einem Container mit id="filter") ausgelesen und in Kleinschrift umgewandelt. Dadurch wird eine von Groß-/Kleinschreibung unabhängige Suche ermöglicht.
Vor der eigentlichen Filterung wird geprüft, ob eine Filterbedingung eingegeben wurde. Wenn nicht, wird lediglich die is-filtered
Klasse vom main-Element entfernt. Es bleibt dem CSS überlassen, daraus die ungefilterte Darstellung zu erzeugen.
Ist eine Filterbedingung vorhanden, wird im main-Element die is-filtered
Klasse gesetzt und die Artikel durchsucht. Diejenigen Artikel, in deren innerText der Suchbegriff gefunden wird, erhalten die is-relevant
Klasse. Von den übrigen wird sie entfernt. Die toggle Methode der classList
ermöglicht mit ihrem zweiten Parameter ein gezieltes Setzen oder Entfernen einer Klasse.
eine übereifrige Suche bremsen
Damit das Suchscript nicht bereits nach dem ersten eingegebenen Zeichen sucht, bauen wir einen einfachen Debouncer ein. Dazu nutzen wir den SetTimeout-Timer und die Möglichkeit, einen gestarteten Timer mit ClearTimeout wieder zu entfernen.
let typingTimer;
let typeInterval = 500;
let searchInput = document.querySelector('#search');
searchInput.addEventListener('input', () => {
clearTimeout(typingTimer);
typingTimer = setTimeout(liveSearch, typeInterval);
Mit setTimeout() wird die Funktion liveSearch()
erst nach einem bestimmten Zeitraum aufgerufen, den Sie in der Variable typeInterval
festlegen können. Tippt der Anwender ein weiteres Zeichen, bevor die Suche begonnen wurde, so wird der bestehende Timer wieder gelöscht.
Alternativtexte berücksichtigen
In der Webseite enthaltene Bilder müssen einen Alternativtext beinhalten, der nicht nur für Screenreader, sondern eben auch für Suchmaschinen und Suchscripte genutzt werden kann. Das soll nun noch ergänzt werden:
<article id="de29664">
<h2>Vogelpark Walsrode</h2>
<p>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Vogelpark_Walsrode_2012_%28140%29.jpg/640px-Vogelpark_Walsrode_2012_%28140%29.jpg" alt="Tukan im Vogelpark Walsrode">
Am Vogelpark
29664 Walsrode
<span hidden>Tipp</span>
</p>
</article>
Um neben dem Textinhalt der Textauszeichnungselemente auch den eigentlich „unsichtbaren“ Alternativtext von Bildern zu durchsuchen, muss dieser ebenfalls erfasst werden. Die Suchfunktion wird damit deutlich umfangreicher, deshalb ist die eigentliche Relevanzermittlung für einen Artikel in eine weitere Funktion ausgelagert worden. Das Codebeispiel ist im Übrigen auf den relevanten Teil reduziert worden, den vollständigen Code finden Sie mit "ausprobieren" im Frickl.
function liveSearch() {
// ...
let alle_artikel = main.querySelectorAll('article');
let filterbegriff = document.querySelector('#filter input').value.toLocaleLowerCase();
// ...
for (let artikel of alle_artikel) {
artikel.classList.toggle('is-relevant', isArticleRelevant(artikel, filterbegriff));
}
}
// Durchsuchen eines Artikels auf den Filterbegriff
function isArticleRelevant(artikel, filterbegriff) {
// Wenn der Suchbegriff als (sichtbarer) Text auftaucht, den Artikel als Treffer markieren
if (artikel.innerText.toLocaleLowerCase().includes(filterbegriff)) {
return true;
}
// Wenn nicht, auch die alt-Texte der Bilder durchsuchen
let bilder = artikel.querySelectorAll("img");
for (let bild of bilder) {
if (bild.alt.toLocalLowerCase().includes(filterbegriff)) {
return true;
}
}
// Nichts gefunden, nicht relevant
return false;
}
Ergebnisanzeige
Da sich die Webseite nach jeder Suche ändert, dies z.B. beim Suchbegriff „Berlin“ aber nicht gleich offensichtlich ist, kann es empfehlenswert sein, in einer Status Message die Anzahl der Suchtreffer anzuzeigen [4]
<div role="status">5 Ergebnisse </div>
Combo Box
Eine Combobox ist ein Widget, das aus der Kombination von zwei verschiedenen Elementen besteht:[5]
- ein einzeiliges Textfeld und
- ein zugehöriges Popup-Element, das dem Benutzer hilft, den Wert des Textfeldes einzustellen. Das Popup-Element kann eine Listbox, ein Grid, ein Baum oder ein Dialog sein. Viele Implementierungen enthalten auch ein drittes optionales Element - eine grafische Schaltfläche neben dem Textfeld, die die Verfügbarkeit des Popup-Fensters anzeigt. Wenn die Schaltfläche aktiviert wird, wird das Popup angezeigt, wenn Vorschläge verfügbar sind.[6]
Im Forum wurde gefragt, wie man ein oben vorgestelltes Suchfeld mit einer Umkreissuche und einer Auto-Vervollständigung von Adressen kombiniert. Hier gibt es mehrere serverseitige Alternativen, die den Umfang dieses Tutorials aber sprengen würden.[7][8]
Suchformulare mit CSS gestalten
Auch eine noch so ausgeklügelte Navigation und ein übersichtlicher Seitenaufbau können verhindern, dass Benutzer Ihrer Webseite gewünschte Inhalte nicht auf Anhieb finden. Hier ist ein schnell auffindbares Suchformular nötig, damit vorhandene Inhalte auch genutzt werden können.
In Formulare/Was ist ein Webformular? erfahren Sie, was beim Absenden eines Suchformular passiert. In diesem Kapitel lernen Sie, wie Sie Suchformulare bedienungsfreundlicher gestalten, damit Nutzer Ihrer Webseite gewünschte Inhalte besser finden.
animierte Suchfelder
Häufig soll ein Suchfeld in ein bestehendes Layout eingepasst werden und die Breite etwa eines Navigationslinks oder einer Sidebar einnehmen. Andererseits sollen bei einer Suche auch lange Eingaben vollständig zu sehen sein. Dies können Sie erreichen, indem Sie das Suchfeld mit CSS anders gestalten, wenn es durch eine Eingabe den focus erhält.
<label for="suche">Suchbegriff eingeben</label>
<input type="search" id="suche" placeholder="Suche...">
Das Eingabefeld vom type="search"
erhält mit dem placeholder-Attribut einen sichtbaren Hinweis. Daneben wird mit dem label-Element eine Beschriftung hinzugefügt, die mit einem for-Attribut mit dem Eingabefeld verbunden wird.
Sie könnten auf das for-Attribut verzichten, wenn Sie das Eingabefeld innerhalb des label notieren. Allerdings ist die hier verwendete Reihenfolge für das spätere Gestalten des label wichtig.
#suche {
border: 2px solid #999;
border-radius: 0.5em;;
font-size: 1.2em;
width: 10em;
transition: width 0.5s ease-in-out;
}
#suche:focus {
font-size: 1.5em;
width: 50%;
}
Das Eingabefeld erhält einen dickeren grauen, abgerundeten Rand. Die Schriftgröße wird erhöht. Die Breite ist abhängig der Schriftgröße 10em breit.
Sobald das Eingabefeld durch die Maus oder Tastatur angesteuert wird, erhält es den Fokus. Dies kann in CSS als Pseudoklasse mit anderen Formatfestlegungen definiert werden. So erhält das Suchfeld eine größere Schriftgröße und eine Breite von 50%. Durch die transition-Eigenschaft wird ein weicher Übergang von einer halben Sekunde erreicht.
Suchsymbol
Eine Lupe gilt als allgemein verständliches Symbol für ein Suchformular. Eine Einbindung einer externen Rastergrafik mit background-image würde aber einen zusätzlichen HTTP-Request benötigen.
Eleganter wäre die Darstellung eines Unicode-Zeichens, das stets passend skaliert. Es gibt die Unicode-Symbole U+1F50D LEFT-POINTING MAGNIFYING GLASS (🔍) und U+1F50E RIGHT-POINTING MAGNIFYING GLASS (🔎), die aber nicht in allen Schriftarten umgesetzt sind. Darüber hinaus darf input als replaced element keinen, auch keinen generierten Inhalt erhalten. Dies ist wichtig, da ein Unicode-Zeichen nicht als Hintergrundbild, sondern als (Text)Inhalt eines Pseudoelements eingebunden würde.
Aus diesem Grund wird im vorliegenden Beispiel eine base64-codierte SVG-Grafik in das CSS eingebunden.
#suche {
width: 10em;
height: 60px;
border: 2px solid #999;
border-radius: 0.5em;
font-size: 1.2em;
transition: width 0.5s ease-in-out;
background:url('data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAASAAD
...
/pcwn9yppSVGRajT8fky+QWgk0+qdcu77uD5lZAAAAAAAA6Ux3AAEV6zGTp3RS5tlfaufCgBQf/9k=') no-repeat right;
}
#suche:focus {
font-size: 1.5em;
width: 50%;
}
- css-tricks: building-resizeable-components-relative-css-units
- tutsplus: css-experiments-with-a-search-form-input-and-button
minimalistische Variante
#suche {
width: 10em;
border: none;
border-bottom: 2px solid #999;
font-size: 1.2em;
transition: width 0.5s ease-in-out;
}
#suche:focus {
font-size: 1.5em;
width: 50%;
}
Suchvorschläge mit datalist
Dieses Beispiel beschreibt, wie Sie in einem Eingabefeld die Eingabe durch Vorschläge aus einer Liste unterstützen können. Der Anwender kann diese Vorschläge annehmen, aber auch einen beliebigen anderen Text eingeben.
Im Idealfall werden Sucheingaben durch AjaX automatisch ergänzt. HTML5 kennt als Ergänzung das autocomplete-Attribut, das dann aus bisherigen Eingaben des Benutzers einen Wert errät und vorschlägt.
Darüberhinaus können Sie dem Benutzer mit dem datalist-Element von Ihnen gewählte, häufig verwendete Suchbegriffe vorschlagen.
<form action="#">
<p>
<label>
Vogelart
<input type="search" list="Vögel">
<datalist id="Vögel">
<option value="Amsel">
<option value="Buntspecht">
<option value="Drossel">
<option value="Eisvogel">
<option value="Fink">
<option value="Graugans">
<option value="Meise">
<option value="Spatz">
<option value="Specht">
</datalist>
</label>
<button>finden!</button>
</p>
</form>
Hier ist ein Eingabefeld vom Typ search
zu sehen, welches als Eingabemöglichkeiten verschiedene Vogelnamen vorschlägt. Der Zusammenhang zwischen dem Eingabefeld und der Liste an Vorschlägen wird dadurch hergestellt, dass der Bezeichner Vögel
sowohl im list
-Attribut des input
-Elements, als auch im id
-Attribut des datalist
-Elements steht.
Weblinks
- ↑ SELF-Forum: Suchfunktion auf Homepage
- ↑ css-tricks: In-Page Filtered Search With Vanilla JavaScript von Hilman Ramadhan, Oct 26, 2021
- ↑ Search Vs. Filter- what is the difference (ux.stackexchange.com)
- ↑ W3C: Using role=status to present status messages
- ↑ W3C: role="combobox" WAI-ARIA
- ↑ W3C: 3.8 Combo Box WAI-ARIA Authoring Practices 1.1
W3C Working Group Note 14 August 2019 - ↑ https://wet-boew.github.io/wet-boew-documentation/research/1-datalist-JSON-suggestion.html
- ↑ HTML Combobox With JavaScript and CSS | Combobox Types & Patterns
Siehe auch
- search (Begriffsklärung)