Signatur
Beschreibung
Die Eigenschaft location.hash enthält den Fragment-Bezeichner der aktuellen Dokument-URL einschließlich des führenden #. Hat die URL kein Fragment oder nur ein leeres (https://example.com/#), ist der Wert eine leere Zeichenkette "".
Die Eigenschaft lässt sich auch schreiben. Beim Setzen wird das Fragment geändert, ohne dass die Seite neu geladen wird. Der Browser scrollt zum Element mit passender id (bzw. einem <a name>), legt einen neuen Eintrag im Verlauf an und löst das Ereignis hashchange auf window aus. Das führende # kannst du beim Setzen weglassen – der Browser ergänzt es.
Typische Einsatzzwecke sind Sprungmarken innerhalb langer Seiten, das Speichern einfacher Zustände in der URL (z. B. aktiver Tab), sowie einfache hashbasierte Router in Single-Page-Anwendungen. Für Routing ohne # ist die History-API heute meist die bessere Wahl.
Wichtig: Der Fragment-Teil wird nie an den Server gesendet. Er existiert nur im Browser und ist deshalb serverseitig nicht auswertbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $wert | string | Nur beim Setzen: Neues Fragment, mit oder ohne führendes #. Sonderzeichen werden prozentkodiert. |
Rückgabewert
# (z. B. "#faq") oder "", wenn kein bzw. ein leeres Fragment vorhanden ist. Der Wert ist prozentkodiert.Beispiele
Fragment auslesen und dekodieren
// URL: https://example.com/doku#%C3%9Cbersicht
const roh = location.hash; // "#%C3%9Cbersicht"
const fragment = decodeURIComponent(roh.slice(1));
console.log(roh);
console.log(fragment);
Aktiven Tab in der URL merken
const tabs = document.querySelectorAll('[role="tab"]');
const aktiviereTab = (id) => {
tabs.forEach((tab) => {
tab.setAttribute('aria-selected', String(tab.dataset.tab === id));
});
};
tabs.forEach((tab) => {
tab.addEventListener('click', () => {
location.hash = tab.dataset.tab; // '#' wird automatisch ergänzt
});
});
// Beim Laden und bei Zurück/Vor den Zustand wiederherstellen
const sync = () => aktiviereTab(location.hash.slice(1) || 'allgemein');
window.addEventListener('hashchange', sync);
sync();
Minimaler Hash-Router
const routen = {
'': () => '<h1>Startseite</h1>',
'#/kontakt': () => '<h1>Kontakt</h1>',
'#/impressum': () => '<h1>Impressum</h1>'
};
const render = () => {
const ansicht = routen[location.hash] ?? (() => '<h1>404 – nicht gefunden</h1>');
document.querySelector('#app').textContent = '';
document.querySelector('#app').insertAdjacentHTML('beforeend', ansicht());
};
window.addEventListener('hashchange', render);
window.addEventListener('DOMContentLoaded', render);
Fragment entfernen ohne Neuladen und ohne Verlaufseintrag
// location.hash = '' lässt ein '#' in der URL stehen
// Sauber entfernen mit der History-API:
const entferneHash = () => {
history.replaceState(null, '', location.pathname + location.search);
};
console.log(location.href); // https://example.com/seite?x=1#abschnitt
entferneHash();
console.log(location.href);
// Wichtig · Fallstricke
- Kodierung: Der Rückgabewert ist prozentkodiert. Vor der Anzeige oder dem Vergleich mit
decodeURIComponent()dekodieren (ggf. intry/catch, da fehlerhafte Sequenzen einenURIErrorwerfen). - Leeres Fragment:
https://example.com/#undhttps://example.com/liefern beide"". Setzt manlocation.hash = "", bleibt ein#in der URL stehen – zum vollständigen Entfernenhistory.replaceState()nutzen. - Verlauf & Scrollen: Jede Zuweisung erzeugt einen neuen Verlaufseintrag und scrollt zum Ziel-Element. Wer beides vermeiden will, verwendet
history.replaceState()– das löst allerdings keinhashchangeaus. - Gleicher Wert: Wird derselbe Hash erneut gesetzt, feuert kein
hashchange. - Sicherheit (XSS): Der Hash ist vollständig vom Nutzer bzw. Angreifer kontrollierbar (DOM-basiertes XSS). Niemals ungeprüft in
innerHTML,document.write(),eval()oder als Selektor inquerySelector()verwenden – für SelektorenCSS.escape()oder besserdocument.getElementById()einsetzen. Da der Hash nicht an den Server gesendet wird, taucht er in Server-Logs nicht auf und wird von serverseitigen Filtern nicht erfasst. - Kompatibilität: Wird von allen Browsern unterstützt. Für beliebige URLs (nicht nur die aktuelle) bietet
URL.prototype.hashdieselbe Funktionalität.