Start · Sprachen · JavaScript · Referenz · Document.hidden

Document.hidden

Eigenschaft

Schreibgeschützte Eigenschaft, die <code>true</code> liefert, wenn die Seite aktuell nicht sichtbar ist (z. B. Hintergrund-Tab oder minimiertes Fenster).

seit JavaScript Page Visibility API — Baseline: alle modernen Brow Kategorie: webapi

Signatur

get Document.hidden

Beschreibung

document.hidden ist Teil der Page Visibility API und gibt an, ob die aktuelle Seite für den Nutzer verborgen ist. Das ist der Fall, wenn der Tab im Hintergrund liegt, das Browserfenster minimiert ist, das Betriebssystem den Bildschirm gesperrt hat oder die Seite gerade entladen bzw. in den Back/Forward-Cache verschoben wird.

Typische Einsatzzwecke sind Ressourcen sparen und Nutzerfreundlichkeit: Animationen, Polling-Anfragen oder Videowiedergabe pausieren, sobald niemand zusieht; Analyse-Daten beim Verlassen senden; Benachrichtigungen nur dann anzeigen, wenn der Nutzer die Seite nicht gerade betrachtet.

Die Eigenschaft ist lediglich eine Momentaufnahme. Um auf Änderungen zu reagieren, lauscht man auf das Ereignis visibilitychange am document und liest darin document.hidden oder das ausführlichere document.visibilityState aus. Der Wert entspricht document.visibilityState !== "visible".

Beispiele

Aktuellen Sichtbarkeitszustand abfragen

// Beim Laden prüfen, ob der Tab im Vordergrund geöffnet wurde
if (document.hidden) {
  console.log('Seite wurde im Hintergrund geöffnet');
} else {
  console.log('Seite ist sichtbar');
}
Seite ist sichtbar

Video pausieren, wenn der Tab verlassen wird

const video = document.querySelector('video');

const handleVisibility = () => {
  if (document.hidden) {
    video.pause();
  } else {
    video.play().catch(() => {
      // Autoplay kann vom Browser blockiert werden
    });
  }
};

document.addEventListener('visibilitychange', handleVisibility);

// Später wieder entfernen, z. B. beim Abbau einer Komponente
// document.removeEventListener('visibilitychange', handleVisibility);

Polling nur bei sichtbarer Seite

let timerId = null;

const fetchUpdates = async () => {
  const res = await fetch('/api/updates');
  const data = await res.json();
  console.log('Neue Einträge:', data.length);
};

const startPolling = () => {
  if (timerId === null) {
    fetchUpdates();
    timerId = setInterval(fetchUpdates, 10_000);
  }
};

const stopPolling = () => {
  clearInterval(timerId);
  timerId = null;
};

document.addEventListener('visibilitychange', () => {
  document.hidden ? stopPolling() : startPolling();
});

if (!document.hidden) startPolling();
Neue Einträge: 3

Analysedaten beim Verbergen zuverlässig senden

document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    const payload = JSON.stringify({ event: 'session_end', ts: Date.now() });
    // sendBeacon überlebt auch das Schließen des Tabs
    navigator.sendBeacon('/analytics', payload);
  }
});

// Wichtig · Fallstricke

  • Schreibgeschützt: Eine Zuweisung wie document.hidden = true wird still ignoriert (im Strict Mode ohne Fehler, da nur ein Getter existiert).
  • Nicht gleich „Fenster hat keinen Fokus“: Ein sichtbares, aber nicht fokussiertes Fenster (z. B. neben einem anderen Fenster) liefert false. Für Fokus nutzt man document.hasFocus() bzw. die Ereignisse focus/blur.
  • Verdeckte Fenster: Ob ein vollständig von anderen Fenstern überdecktes Browserfenster als verborgen gilt, hängt von Browser und Betriebssystem ab — verlassen Sie sich nicht darauf.
  • Beenden der Sitzung: visibilitychange mit document.hidden === true ist das zuverlässigste Signal für das „letzte“ Ereignis einer Seite, besonders auf Mobilgeräten; unload und beforeunload werden dort oft nicht ausgelöst.
  • Timer-Drosselung: Browser drosseln setInterval/setTimeout in verborgenen Tabs ohnehin stark und pausieren requestAnimationFrame — trotzdem sollte man teure Arbeit aktiv stoppen.
  • Kompatibilität: In allen modernen Browsern ohne Präfix verfügbar. Sehr alte Versionen (Chrome < 33, IE 10) nutzten webkitHidden bzw. msHidden. Der veraltete Zustand "prerender" von visibilityState wird nicht mehr verwendet.