Site Search für eine persönliche Website — Die erinnerte Seite wiederfinden
Manche Leser kommen über eine Suchmaschine, lesen eine Seite und gehen wieder. Andere erinnern sich Monate später an einen Satz und kehren zurück, wissen aber weder Titel noch URL. Eine persönliche Website mag klein sein. Wenn sie jedoch Notizen, Tutorials und Essays aus mehreren Jahren enthält, kann die Suche nach einer vage erinnerten Seite so schwierig werden wie die Suche nach einem bestimmten Schraubendreher in einer unbeschrifteten Schublade.
Eine Site Search bietet diesen Lesern einen direkten Weg zurück ins Archiv. Sie muss weder Google nachahmen noch einen großen Hosted Service einführen. Für viele persönliche Websites reicht ein kleiner, verständlicher Search Index aus. Dieser Leitfaden erklärt die möglichen Ansätze, entwickelt eine client-side Implementierung und behandelt jene Details, die aus einem Textfeld einen nützlichen Teil der Website machen.
Search ist Navigation für ein unvollkommenes Gedächtnis
Menüs funktionieren, wenn Besucher unsere Kategorien verstehen. Archivseiten helfen, wenn sie sich an ein Datum erinnern. Tags funktionieren, wenn Autor und Leser dasselbe Vokabular verwenden. Search löst die unordentlichere Situation: Jemand erinnert sich an „diesen Artikel über einen alten Link“, aber nicht daran, dass der Titel „link rot“ enthält. Besucher können das Ziel mit ihren eigenen Worten beschreiben.
Deshalb sollte Search die Navigation ergänzen und nicht ersetzen. Ein klares Menü zeigt neuen Besuchern weiterhin, welche Inhalte vorhanden sind, während Search wiederkehrenden Lesern hilft, etwas Bestimmtes zurückzuholen. Man kann es mit einer Küche vergleichen: Beschriftungen an den Schränken schaffen Struktur. Trotzdem ist es hilfreich, fragen zu können, wo die Kaffeefilter liegen, wenn man diese Struktur noch nicht im Kopf hat.
Den passenden Ansatz für das Archiv wählen
Drei Ansätze sind üblich. Eine server-side Search fragt bei jedem Suchvorgang eine Datenbank ab. Sie skaliert gut und kann vollständige Inhalte präzise bewerten, benötigt jedoch Backend Code, input validation, rate limiting und Wartung. Ein Hosted Service kann typo tolerance und ausgefeiltes Ranking liefern, schafft aber eine externe Abhängigkeit und übermittelt Suchanfragen möglicherweise an ein anderes Unternehmen.
Eine client-side Search lädt einen kompakten Index herunter und filtert ihn im Browser. Sie eignet sich sehr gut für eine statische oder überschaubare persönliche Website: Es ist kein Search Server erforderlich, Anfragen bleiben auf dem Gerät des Lesers und die Funktion kann mit einer gespeicherten Kopie weiterarbeiten. Die wichtigste Grenze ist die Größe. Wenn das JSON mehrere Megabyte oder Tausende lange Dokumente enthält, wird das Laden und Parsen bei jedem Besuch verschwenderisch.
Am Anfang genügen Titel, Zusammenfassungen, URLs und eventuell Tags. Ein solcher kleiner Index liefert oft bessere Ergebnisse als jedes einzelne Wort, weil er hervorhebt, worum es auf einer Seite tatsächlich geht. Full-text Search lässt sich später ergänzen, wenn die tatsächliche Nutzung zeigt, dass Metadaten nicht ausreichen.
Einen kleinen, eindeutigen Search Index erstellen
Der Index kann während des normalen Build- oder Publishing-Prozesses erzeugt werden. Wenn Artikel bereits in einem CMS liegen, sollte er nicht manuell gepflegt werden; manuelle Kopien weichen früher oder später ab. Exportiert werden ausschließlich veröffentlichte öffentliche Seiten, Zusammenfassungen ohne HTML und canonical URLs. Eine einfache Datei kann so aussehen:
[
{
"title": "Preventing Link Rot on a Personal Website",
"url": "/preventing-link-rot-personal-website/",
"summary": "Practical ways to preserve references and repair old links.",
"tags": ["web", "maintenance"]
},
{
"title": "A Useful 404 Page for a Personal Website",
"url": "/useful-404-page-personal-website/",
"summary": "Turn a dead end into a helpful route back into the site.",
"tags": ["web", "navigation"]
}
]
Das Schema darf ruhig langweilig bleiben. Stabile Felder lassen sich leichter erzeugen, cachen und verwenden als eine zu früh optimierte, raffinierte Struktur. Private Entwürfe und vertrauliche Metadaten müssen ausgeschlossen werden. Ein Search Index ist ein öffentliches Dokument, auch wenn keine sichtbare Seite direkt darauf verweist.
Ein zugängliches Search Form erstellen
Das Interface sollte bereits sinnvoll sein, bevor JavaScript ausgeführt wird. Dafür braucht es ein echtes <form>, ein sichtbares Label und ein Search Input. Falls ein Server Endpoint existiert, kann das Formular als Fallback dorthin senden. Andernfalls sollte verständlich erklärt werden, dass die interaktive Suche JavaScript benötigt, statt einen Button anzuzeigen, der ohne Rückmeldung nichts tut.
<form id="site-search" role="search">
<label for="search-query">Search this site</label>
<input id="search-query" name="q" type="search"
autocomplete="off" minlength="2">
<button type="submit">Search</button>
</form>
<p id="search-status" aria-live="polite"></p>
<ol id="search-results"></ol>
Das Label kann nicht durch placeholder text ersetzt werden: Ein Placeholder verschwindet beim Tippen und besitzt häufig einen schwachen Kontrast. Der Live Status teilt Screen-Reader-Nutzern die Ergebniszahl mit, ohne den Keyboard Focus unerwartet zu verschieben. Eine ordered list verleiht den Ergebnissen eine sinnvolle Struktur.
Filtern und bewerten, ohne die Logik zu verstecken
Für ein kleines Archiv ist transparentes Ranking besser als ein komplizierter Algorithmus. Die Groß- und Kleinschreibung wird normalisiert, die Anfrage in Begriffe zerlegt und jeder Begriff muss irgendwo vorkommen. Treffer im Titel erhalten ein höheres Gewicht als Treffer in Zusammenfassung oder Tags. Die folgende Implementierung lädt den Index erst nach einer gültigen Suche und zeigt Ergebnisse an, ohne Indextext als HTML einzufügen:
const form = document.querySelector('#site-search');
const input = document.querySelector('#search-query');
const status = document.querySelector('#search-status');
const results = document.querySelector('#search-results');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const terms = input.value.toLowerCase().trim().split(/\s+/).filter(Boolean);
if (terms.join('').length < 2) return;
const response = await fetch('/search-index.json');
if (!response.ok) throw new Error('Search index unavailable');
const pages = await response.json();
const matches = pages.map((page) => {
const title = page.title.toLowerCase();
const details = `${page.summary} ${page.tags.join(' ')}`.toLowerCase();
if (!terms.every((term) => title.includes(term) || details.includes(term))) return null;
const score = terms.reduce((sum, term) => sum +
(title.includes(term) ? 10 : 0) + (details.includes(term) ? 1 : 0), 0);
return { page, score };
}).filter(Boolean).sort((a, b) => b.score - a.score).slice(0, 20);
results.replaceChildren(...matches.map(({ page }) => {
const item = document.createElement('li');
const link = document.createElement('a');
link.href = page.url;
link.textContent = page.title;
const summary = document.createElement('p');
summary.textContent = page.summary;
item.append(link, summary);
return item;
}));
status.textContent = `${matches.length} result(s) found`;
});
Die Verwendung von textContent ist wichtig. Selbst wenn der Index aus dem eigenen CMS stammt, verhindert die Behandlung als Text, dass ein versehentliches HTML-Fragment zu Markup wird. In production sollte ein try...catch ergänzt werden, damit ein Netzwerkfehler als verständliche Meldung statt als unhandled error erscheint.
Leere Zustände wirklich hilfreich gestalten
„No results“ ist technisch korrekt, aber kaum hilfreich. Die Oberfläche kann empfehlen, ein Wort zu entfernen, die Schreibweise zu prüfen oder das Archiv zu öffnen. Mit ?q=... bleibt die Anfrage in der URL, sodass Ergebnisse als Lesezeichen gespeichert werden können und der Zurück-Button natürlich funktioniert. Bei Treffern sollten Anzahl und genügend Kontext angezeigt werden, um Seiten mit ähnlichen Titeln unterscheiden zu können.
Treffer sollten nicht durch das Zusammensetzen von raw HTML hervorgehoben werden. Ist Highlighting wichtig, wird der Text in Nodes zerlegt und passende Segmente werden sicher umschlossen. Auch eine Anfrage bei jedem keystroke ist ohne Debounce ungünstig. Ein Submit-first Design wirkt ruhiger, reduziert die Arbeit auf schwächeren Smartphones und bleibt leicht verständlich.
Performance, Privatsphäre und mehrsprachige Inhalte
Der Index sollte komprimiert und mit sinnvollen caching headers ausgeliefert werden. Wenn sich Inhalte ändern, benötigt er eine neue Revision oder einen aktualisierten Validator. Er wird bei Bedarf geladen, statt den initial payload jeder Seite zu vergrößern. Gemessen werden sollte die compressed transfer size; diese Zahl ist hilfreicher als die Vermutung, ein Index sei „klein“.
Client-side Search hält den Ausdruck selbst lokal. Gewöhnliche Server Logs können die Anfrage jedoch erfassen, wenn sie in der URL steht. Ob das akzeptabel ist, muss bewusst entschieden werden, und search terms sollten standardmäßig nicht an Analytics gesendet werden. In Suchfeldern stehen manchmal überraschend persönliche Textfragmente.
Eine mehrsprachige Website sollte entweder einen Index pro Locale veröffentlichen, etwa /id/search-index.json, oder ein Locale Field aufnehmen und vor dem Ranking filtern. Alle Sprachen wahllos zu mischen ist keine gute Lösung. Wer auf Indonesisch sucht, sollte passende Ergebnisse nicht unter englischen und deutschen Seiten verlieren. Zudem kann sprachspezifische Tokenization später unterschiedliche Regeln erfordern.
Die Wege testen, die Menschen tatsächlich nutzen
Eine kurze Testliste sollte Begriffe aus echten Artikeln enthalten. Sinnvolle Fälle sind exakte Titel, ein Ausdruck ausschließlich aus einer Zusammenfassung, unterschiedliche Großschreibung, zusätzliche Leerzeichen, ein Tippfehler, eine leere Anfrage und ein Begriff ohne Treffer. Auch keyboard-only Bedienung und ein schmales mobile viewport gehören dazu. Nach dem Laden kann die Netzwerkverbindung getrennt werden, um die Verständlichkeit der Fehlermeldung zu prüfen.
Search Quality ist nicht bloß die Anzahl der Treffer. Die gewünschte Seite sollte weit oben erscheinen, veraltete oder private Seiten dürfen niemals auftauchen und ein neuer Artikel muss zeitnah in den Index gelangen. Index URLs sollten regelmäßig auf Redirects und 404-Antworten geprüft werden; Search darf nicht zu einer weiteren Karte werden, die auf gesperrte Straßen zeigt.
Eine kleine Search-Funktion darf klein bleiben
Eine nützliche Search für eine persönliche Website benötigt weder Cluster noch opaque Ranking Model oder Surveillance. Sie benötigt einen sauberen Index, ein zugängliches Formular, vorhersehbares Matching, hilfreiche leere Zustände und einen Publishing Process, der alles aktuell hält. Metadaten und client-side Filtering sind ein guter Anfang. Komplexität sollte erst hinzukommen, wenn Archiv und Leser einen tatsächlichen Bedarf zeigen.
Wer eine persönliche Website betreibt, kann probeweise nach einem Artikel suchen, an den er sich nur vage erinnert, statt nach einem bereits bekannten Titel. Dieses kleine Experiment zeigt, ob die Navigation das menschliche Gedächtnis unterstützt. Berichte in den Kommentaren, was funktioniert hat, was nicht oder wie du deine eigene Search gebaut hast; vielleicht sucht ein anderer Website-Betreiber gerade nach genau diesem fehlenden Baustein.
