Wir haben noch nicht alle älteren Artikel nachbearbeitet. Das bezieht sich in der Regel nur auf die Codebeispiele, die noch nicht optimal dargestellt werden.
Der perfekte Suchschlitz
Beinahe jede Website im Netz bietet die Möglichkeit einer einfachen Volltextsuche über die Gesamtheit der Inhalte. Gut so! Worauf man bei der Gestaltung dieses kleinen Formulars achten kann, klärt dieser Artikel von Gerrit van Aaken.
Google macht es allen seit nunmehr 10 Jahren vor: Eine gute Suche ist auf das Wesentliche reduziert, nämlich ein Eingabefeld für den Suchbegriff und einen Knopf zum Auslösen der Suchanfrage. Warum sollte man mehr benötigen? Oder wann hast du das letzte mal eine komplexere »Erweiterte Suche« mit Genuss bedient? Eben!
Eine valide Basis
Wenn wir uns an die Webstandards halten, sieht der valide XHTML-1.0-Code für eine schlichte Suche folgendermaßen aus:
<form action="/">
<div>
<input type="text" />
<input type="submit" value="Suchen" />
</div>
</form>
Das div
-Element benötigen wir, weil laut Spezifikation die input
-Elemente keine direkten Kindelemente von form
sein dürfen.
Doch natürlich soll das nicht alles gewesen sein! Wir wollen nun dieses Ausgangsmaterial mit einigen Nettigkeiten anreichern, um es allen Nutzern bequemer und einfacher zu machen. Los geht’s!
Ein bisschen Semantik, bitte!
In erster Linie für Screenreader und andere Zugriffshilfen wollen wir unseren Code mit ein wenig »Bedeutung« aufladen, damit man nicht nur visuell erkennen kann, dass es sich hier um eine astreine Volltextsuche handelt. Das div
-Element, welches nur aus Gründen der Validität platziert wurde, weicht einem fieldset
-Element, damit die beiden Input-Elemente schön zusammengehörig erscheinen. Ein legend
-Element macht deutlich, worum es hier geht. Und mit einem label
kennzeichnen wir die Funktion des Eingabefeldes. Der Submit-Button benötigt kein eigenes Label, da seine Funktion aus seinem value
-Attribut bereits klar hervorgeht.
<form action="/">
<fieldset>
<legend>Volltextsuche</legend>
<label for="suchbegriff">Suchbegriff</label>
<input type="text" id="suchbegriff" />
<input type="submit" value="Suchen" />
</fieldset>
</form>
Geht’s noch ein wenig hübscher?
Über das Stylen von Formularen kann man ganze Bücher füllen, gerade was die unterschiedliche Darstellung in den Browsern angeht. Das soll jedoch nicht unser Thema sein – hier seien nur einige kleine Maßnahmen erwähnt: Der Rahmen des fieldset
-Elements wird ausgeblendet, ebenso die Legende – diese beiden Elemente sind für normal sehende Nutzer zuviel des Guten. Ein Problem gibt es beim legend
-Element: Es lässt sich nicht per absoluter Positionierung verstecken, und ein simples display: none;
wäre nicht gut für Menschen, die z. B. auf Screenreader angewiesen sind. Deshalb setzen wir ein zusätzliches span-Element innerhalb der Legend ein, um diese sauber verstecken zu können. Wer puristisch veranlagt ist, kann auch noch das label visuell ausblenden – wir werden später als Ersatz ein »Pseudo-Label« als vorbelegten Inhalt des Input-Feldes einfügen. Button und Input-Feld bekommen leicht räumlich wirkende Rahmenfarben und eine Füllung spendiert.
<legend><span>Volltextsuche</span></legend>
fieldset {
border: none;
}
legend, label span {
position: absolute;
left: -999em;
}
input[type=text] {
border: 1px solid #444;
border-color: #444 #888 #888 #444;
background: #fff url(verlauf.png) 0 -6px repeat-x;
}
input[type=submit] {
border: 1px solid #000;
border-color: #da0000 #6c0000 #6c0000 #da0000;
background: #900;
color: #fff;
}
Interaktives Verhalten per CSS-Pseudoklassen
Eigentlich ist zwar JavaScript für das interaktive Verhalten einer Website zuständig. Doch über die sogenannten Pseudoklassen lassen sich auch per reinem CSS nette Effekte erzielen, die dem Nutzer ein angenehmes Gefühl vermitteln. Zunächst einmal ersetzen wir den Mauszeiger, wenn man über den Button fährt – er soll eine Zeigefingerform bekommen (pointer
), damit klar wird, dass es was zu klicken gibt. Dann kümmern wir uns um das Aussehen des aktiven Zustandes von Textfeld (wird abgedunkelt durch Verschieben des Hintergrundverlaufes) und Button (anderer Farbton).
input[type=text]:focus {
border-color: #000 #444 #444 #000;
background-position: 0 0;
}
input[type=submit]:hover {
cursor: pointer;
}
input[type=submit]:focus,
input[type=submit]:active {
background: #6c0000;
}
Hinweis: Der Internet Explorer 6 kennt weder type
-Selektoren noch Pseudoklassen. Da wir hier jedoch nur Kosmetik betreiben, ist dies zu vernachlässigen.
Interaktives Verhalten per JavaScript I
Das i-Tüpfelchen unserer Arbeit soll nun per JavaScript realisiert werden: Wir verzichten ja bewusst sowohl auf eine Legende als auch auf ein Label, wollen aber dennoch dem Nutzer klarmachen, was er mit diesem Suchschlitz anfangen soll. Deshalb schreiben wir einen value
in das Textfeld, welches wir aber später per JavaScript leeren, sobald der Nutzer das Feld anwählt, um selber einen Begriff einzutragen.
<input type="text" id="suchbegriff" value="Suchbegriff" />
Was passiert nun in unserem JavaScript? Zuallererst verzichten wir natürlich auf hässliche Vermischungen von HTML und JavaScript, und somit fallen die HTML-Attribute onfocus
und onblur
flach. Statt dessen verfolgen wir den unaufdringlichen Einsatz von JS: Zunächst machen wir das Textfeld über seine eindeutige ID ausfindig und erstellen eine Objektinstanz mit einem griffigen Namen: myTextfeld
. Dann kleben wir ein Verhalten an dieses Objekt. Dies funktioniert mit dem hier verwendeten addEventListener
nicht in allen Browsern, es soll aber als grundsätzliche Demonstration genügen.
Konkret: Sobald das Objekt myTextfeld
per 'focus' vom Nutzer hervorgehoben/aktiviert wird, soll die Funktion textLeeren
aufgerufen werden, welche direkt darunter notiert ist. Sie leert den Inhalt des Textfeldes, wie der Name schon sagt. (Das dritte Attribut 'false' ist an dieser Stelle nicht relevant.)
myTextfeld = document.getElementById('suchbegriff');
if (document.addEventListener) {
myTextfeld.addEventListener('focus', textLeeren, false);
}
function textLeeren() {
myTextfeld.value = "";
}
Interaktives Verhalten per JavaScript II
Noch schöner wäre es, wenn beim Verlassen des Textfeldes ('blur') auch etwas passieren würde. Und zwar abhängig davon, ob der Nutzer etwas in das Feld geschrieben hat oder nicht! Falls er nur aus Spaß das Feld angeklickt hat, wäre es nett, wenn dort wieder der Ursprungszustand hergestellt würde. Hat er jedoch tatsächlich etwas hineingeschrieben, muss dieser Wert natürlich erhalten bleiben. Um dies zu realisieren, müssen wir bereits beim Betreten des Feldes den dort aktuellen Wert zwischenspeichern, um ihn nachher beim Verlassen des Feldes wieder parat zu haben. Insgesamt sieht unser Skript am Ende dann so aus:
myTextfeld = document.getElementById('suchbegriff');
if (document.addEventListener) {
myTextfeld.addEventListener('focus', textLeeren, false);
myTextfeld.addEventListener('blur', textFuellen, false);
}
function textLeeren() {
mySuchspeicher = myTextfeld.value;
myTextfeld.value = "";
}
function textFuellen() {
if (myTextfeld.value == "") {
myTextfeld.value = mySuchspeicher;
}
}
Fazit
Unsere kleine Volltextsuche hat nun eigentlich alles, was du brauchst: Sie ist valide gegen XHTML 1.0, sie besitzt eine ordentliche Semantik, sieht halbwegs hübsch aus und unterstützt den Nutzer bei der Interaktion. Was will man mehr?
Doch bevor du nun die Finger auf die Tasten STRG+C und STRG+V legst, bitte ich zu bedenken, dass zum einen das verwendete JavaScript nicht vollständig praxistauglich ist – ich wollte lediglich möglichst anschaulich zeigen, was prinzipiell zu tun ist. In vielen Fällen lässt sich das über ein JS-Framework deutlich eleganter und vor allem browserkompatibel umsetzen. Zum anderen sollte man natürlich darüber nachdenken, ob man nicht doch die hier versteckten Elemente legend
und label
gewinnbringend zum Einsatz bringen kann.
Es gibt eben doch keine perfekte Lösung für alle Einsatzgebiete, oder hast du das wirklich geglaubt?
Kommentare
José Stiller
am 09.12.2008 - 08:33
Eine sehr schöne Herangehensweise und ein sehr gutes Beispiel dafür wie man soetwas erstellen sollte! Vielen Dank für den tollen Artikel.
Christian
am 09.12.2008 - 08:34
Danke für den Beitrag. Das man
input
nicht direkt in einform
packen darf war auch mir neu, bisher tat ich das aber eh nie, anders kann ich mir nicht erklären das der Validator nie angeschlagen hat.Christian Heilmann (Webkraut)
am 09.12.2008 - 09:48
Schoen aber perfekt? Gerade bei einem sehr kleinen Formular wie diesem ist ein fieldset Element eher stoerend als hilfreich. Als Screenreader Nutzer muss ich mir ein "Volltextsuche eingabefeld suchbegriff" anhoeren waehrend es ein "eingabefeld suchbegriff" auch getan haette. Weiterhin wird die Legende fuer jedes Formularfeld wiederholt, daher macht es nur Sinn um in einem grossen Formular den Inhalt in sinnige Abschnitte zu trennen anstatt ein einzelnes Feld semantisch zu machen. Das wir das ganze dann auch wieder verstecken ist fuer mich eher uebertriebene Arbeit. Semantik und Barrierefreiheit laesst sich am besten verkaufen wenn man sie auch sieht und dabei was Gutes fuer alle Enduser rauskommt.
Dirk Olbertz
am 09.12.2008 - 10:08
Ganz hilfreich für den User kann es außerdem sein, wenn man den Namen des Inputfeldes "q" nennt. Somit nutzt der Browser für die Autovervollständigung der Suchbegriffe die Google-History der Suche - also natürlich nicht die offizielle Google Website-History, aber die aus dem Browser selbst.
Manuel Bieh (Webkraut)
am 09.12.2008 - 11:28
Also ich finds immer ganz schön wenn solche Eingabefelder, die per Javascript onclick geleert werden, auch erst dann initial gefüllt werden, wenn der Benutzer Javascript aktiviert hat. Also anstatt
value="Suchebegriff"
einfachvalue=""
im Formular, und dannwindow.onload = function() {
textFuellen();
}
Oder spricht da aus eurer Sicht was gegen?
Christian Heilmann (Webkraut)
am 09.12.2008 - 11:41
@Manuel: wenn du das mit nem onload handler machst, ja weil mit dem code hier andere, wichtigere onload handler ueberschrieben werden. Ansonsten, warum nicht.
Markus
am 09.12.2008 - 11:47
... und wenn man dann noch das Attribut defaultValue nutzt, um den Inhalt des Suchfelds wieder auf das Label zurückzusetzen, kann man sich das Zwischenspeichern in einer Variablen sparen.
Markus Wulftange
am 09.12.2008 - 11:55
Ich finde es ganz schön, wenn das Eingabefeld „weiß“, dass ich etwas eingegeben hab. So sollte wenn ich „Suchbegriff“ eingegeben habe dies nicht wieder verschwinden, sobald der Fokus erneut aufs Eingabefeld fällt, beispielsweise:
var input = document.getElementById("some_name");
function textLeeren() {
if (myTextfeld.value == myTextfeld.defaultValue) {
myTextfeld.value = "";
}
}
function textLeeren() {
if (myTextfeld.value != "") {
myTextfeld.defaultValue = "";
}
if (myTextfeld.value == "") {
myTextfeld.value = myTextfeld.defaultValue;
}
}
Ansgar
am 09.12.2008 - 12:53
Zur Verbesserung der Zugänglichkeit im Sinne der Skalierbarkeit - gerade im Internet Explorer klappt es sonst nicht - sollte man noch ein
font-size: 1em;
für die input-Felder vergeben.Daniel
am 10.12.2008 - 00:05
Schöner wäre das Tag zu verwenden statt einen Submit-Button dahingehend umzubiegen. So bleibt zu sagen: Pseudo.
Nico
am 10.12.2008 - 09:38
Ich finde es auch immer ziemlich nervig, wenn ich eine Suche durchgeführt habe, mich aber beim Suchbegriff vertippt habe und Javascript das Suchfeld erstmal leert, wenn ich den Tippfehler korrigieren will. Es sollte also beim Leeren geprüft werden, ob überhabt der defaultValue drinsteht.
Marc
am 30.12.2008 - 08:33
Auch interessant ist der mit (X)HTML5 kommende
search
-Typ fürinput
-Elemente:<input type="search" name="q" />
Vom Safari wird das bereits adäquat unterstützt, in anderen Browsern wird's dank graceful degradation zu einem normalen Textfeld. Und wenn man auf Validität bedacht ist, kann man die
text
-Typen für Suchfelder dank unobtrusive JavaScript durch densearch
-Typen ersetzen.Ein Praxiseinsatz findet sich z.B. bei Wolfgang Bartelme.
Struppi
am 05.01.2009 - 18:34
Ich würd das JS zum leeren so machen:
myTextfeld = document.getElementById('suchbegriff');
if (document.addEventListener) {
myTextfeld.addEventListener('focus', textLeeren, false);
myTextfeld.addEventListener('blur', textFuellen, false);
}
function textLeeren() {
myTextfeld.value = "";
}
function textFuellen() {
if (!myTextfeld.value.length)
myTextfeld.value = myTextfeld.defaultValue;
}
}
defaultValue wird seit IE 3 und Netscape 2 unterstützt, warum also nicht einsetzen.
Die Kommentare sind geschlossen.