Signatur
Beschreibung
window.visualViewport gibt ein VisualViewport-Objekt zurück. Es beschreibt den visuellen Viewport, also den Teil der Seite, den der Nutzer gerade tatsächlich sieht. Anders als der Layout-Viewport (window.innerWidth/innerHeight) wird der visuelle Viewport kleiner, wenn per Pinch gezoomt wird oder die Bildschirmtastatur auf Mobilgeräten einen Teil des Bildschirms verdeckt.
Das Objekt stellt unter anderem width, height, offsetLeft, offsetTop, pageLeft, pageTop und scale bereit. Außerdem löst es die Ereignisse resize und scroll aus (seit Kurzem in Chromium auch scrollend). So lassen sich Elemente trotz Zoom oder eingeblendeter Tastatur korrekt positionieren.
Typische Einsatzfälle:
- Fixierte Toolbars oberhalb der virtuellen Tastatur anzeigen
- Chat-Eingabefelder im sichtbaren Bereich halten
- Tooltips und Overlays beim Pinch-Zoom richtig platzieren
- Zoomstufe über
scaleauslesen
Die Eigenschaft ist schreibgeschützt. Sie liefert null, wenn das Dokument nicht vollständig aktiv ist, zum Beispiel bei einem aus dem DOM entfernten <iframe>.
Rückgabewert
VisualViewport-Objekt des Fensters oder null, wenn das zugehörige Dokument nicht vollständig aktiv ist.Beispiele
Maße und Zoomfaktor auslesen
const vv = window.visualViewport;
if (vv) {
console.log(`Sichtbar: ${Math.round(vv.width)} × ${Math.round(vv.height)} px`);
console.log(`Zoom: ${vv.scale}`);
console.log(`Versatz zum Layout-Viewport: ${vv.offsetLeft}/${vv.offsetTop}`);
} else {
console.log('VisualViewport nicht verfügbar');
}
Toolbar über der Bildschirmtastatur halten
const toolbar = document.querySelector('#toolbar');
const vv = window.visualViewport;
const positionToolbar = () => {
// Abstand vom unteren Rand des Layout-Viewports zum sichtbaren Bereich
const bottomGap = window.innerHeight - (vv.height + vv.offsetTop);
toolbar.style.transform = `translateY(${-Math.max(0, bottomGap)}px)`;
};
if (vv) {
vv.addEventListener('resize', positionToolbar);
vv.addEventListener('scroll', positionToolbar);
positionToolbar();
}
Overlay beim Pinch-Zoom mitskalieren
const badge = document.querySelector('.badge');
const vv = window.visualViewport;
const update = () => {
// Badge bleibt oben links im sichtbaren Bereich und behält seine Größe
badge.style.left = `${vv.offsetLeft}px`;
badge.style.top = `${vv.offsetTop}px`;
badge.style.transform = `scale(${1 / vv.scale})`;
badge.style.transformOrigin = '0 0';
};
vv?.addEventListener('resize', update);
vv?.addEventListener('scroll', update);
// Aufräumen, z. B. beim Unmount einer Komponente
const cleanup = () => {
vv?.removeEventListener('resize', update);
vv?.removeEventListener('scroll', update);
};
// Wichtig · Fallstricke
- Auf
nullprüfen: In abgekoppelten iframes oder inaktiven Dokumenten ist der Wertnull. Verwende Optional Chaining (visualViewport?.width). - Kompatibilität: Chrome/Edge 61+, Safari 13+ und Firefox 91+ unterstützen die Eigenschaft. In älteren Browsern auf
window.innerWidth/innerHeightzurückfallen. - Tastatur-Verhalten: iOS Safari verkleinert beim Öffnen der Tastatur nur den visuellen Viewport, nicht den Layout-Viewport. Deshalb bleibt
window.innerHeightunverändert, undposition: fixed-Elemente können verdeckt werden. Chromium kann dieses Verhalten über das Meta-Attributinteractive-widgetändern. - Performance:
resize- undscroll-Ereignisse feuern während Gesten sehr häufig. Aktualisierungen deshalb bündeln, etwa mitrequestAnimationFrame, und bevorzugttransformstatt layoutauslösender Eigenschaften setzen. - Werte wie
widthundheightsind Gleitkommazahlen in CSS-Pixeln und enthalten keine Scrollleisten.