Signatur
Beschreibung
Das Interface Viewport gehört zur Viewport Segments API. Eine Instanz erhält man über window.viewport. Einen Konstruktor gibt es nicht. Die API ist für faltbare Geräte und Geräte mit zwei Bildschirmen gedacht (z. B. Samsung Galaxy Z Fold oder Microsoft Surface Duo). Dort ist der sichtbare Bereich durch ein Scharnier oder eine Falz in mehrere logische Bereiche geteilt, die sogenannten Segmente.
Die einzige Eigenschaft ist Viewport.segments. Sie ist schreibgeschützt und liefert ein Array von DOMRect-Objekten. Jedes Objekt beschreibt Position (x, y) und Größe (width, height) eines Segments in CSS-Pixeln, relativ zum Layout-Viewport. Ist das Viewport nicht geteilt, enthält das Array genau ein Segment. In eingebetteten Frames (iframe) wird null zurückgegeben.
Die API nutzt man, wenn JavaScript das Layout an die Falz anpassen soll. Beispiele: eine Kartenansicht links und Details rechts, ein Video oben und die Steuerung unten, oder ein Dialog, der nicht über das Scharnier hinweg angezeigt werden soll. Für reine Layout-Aufgaben reicht oft CSS: Die Media Features horizontal-viewport-segments und vertical-viewport-segments sowie die Umgebungsvariablen env(viewport-segment-width x y), env(viewport-segment-left x y) usw. decken dasselbe Modell ab.
Ändert sich die Haltung des Geräts (Aufklappen, Drehen, Wechsel in den Split-Modus), ändern sich auch die Segmente. Ein eigenes Ereignis dafür gibt es nicht. Deshalb liest man segments bei resize neu aus oder hört mit matchMedia() auf Änderungen der Segment-Media-Queries.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $segments | DOMRect[] | null | Schreibgeschützte Eigenschaft (kein Parameter im eigentlichen Sinn): ein Array von DOMRect-Objekten, eines pro Viewport-Segment, geordnet von links nach rechts bzw. von oben nach unten. In eingebetteten Frames null. |
Rückgabewert
window.viewport liefert das Viewport-Objekt des aktuellen Fensters. viewport.segments liefert DOMRect[] oder null.Beispiele
Unterstützung prüfen und Segmente ausgeben
// Viewport-Objekt holen (kein Konstruktor, nur über window.viewport)
if ('viewport' in window && window.viewport.segments) {
const { segments } = window.viewport;
console.log(`Anzahl Segmente: ${segments.length}`);
segments.forEach((rect, i) => {
console.log(`Segment ${i}: x=${rect.x}, y=${rect.y}, ${rect.width}×${rect.height}`);
});
} else {
console.log('Viewport Segments API nicht verfügbar');
}
Zweispaltiges Layout an der Falz ausrichten
const list = document.querySelector('#liste');
const detail = document.querySelector('#detail');
const applyLayout = () => {
const segments = window.viewport?.segments;
if (segments && segments.length === 2 && segments[0].x !== segments[1].x) {
// Nebeneinander liegende Segmente: Liste links, Details rechts
const [left, right] = segments;
Object.assign(list.style, { position: 'fixed', left: `${left.x}px`, width: `${left.width}px` });
Object.assign(detail.style, { position: 'fixed', left: `${right.x}px`, width: `${right.width}px` });
document.body.dataset.layout = 'dual';
} else {
list.removeAttribute('style');
detail.removeAttribute('style');
document.body.dataset.layout = 'single';
}
};
applyLayout();
// Kein eigenes Ereignis: bei resize neu berechnen
window.addEventListener('resize', applyLayout);
Auf Wechsel der Gerätehaltung per matchMedia reagieren
const dualHorizontal = window.matchMedia('(horizontal-viewport-segments: 2)');
const onChange = (event) => {
const count = window.viewport?.segments?.length ?? 1;
console.log(event.matches
? `Aufgeklappt, ${count} Segmente nebeneinander`
: 'Einzelnes Segment');
};
dualHorizontal.addEventListener('change', onChange);
onChange(dualHorizontal); // Anfangszustand auswerten
Dialog nicht über das Scharnier legen
const placeDialog = (dialog) => {
const segments = window.viewport?.segments ?? [];
// Größtes Segment wählen und den Dialog darin zentrieren
const target = segments.reduce(
(best, r) => (r.width * r.height > best.width * best.height ? r : best),
{ x: 0, y: 0, width: innerWidth, height: innerHeight }
);
dialog.style.left = `${target.x + target.width / 2}px`;
dialog.style.top = `${target.y + target.height / 2}px`;
dialog.style.translate = '-50% -50%';
};
placeDialog(document.querySelector('#hinweis'));
// Wichtig · Fallstricke
- Experimentell: Die API ist derzeit nur in Chromium-Browsern ab Version 138 verfügbar (Chrome, Edge, auf Android und Desktop). Firefox und Safari unterstützen sie nicht. Prüfen Sie deshalb immer mit
'viewport' in windowoder optionaler Verkettung (window.viewport?.segments). - Kein Ereignis für Änderungen:
segmentsist eine Momentaufnahme. Lesen Sie den Wert beiresizeneu aus oder nutzen SiematchMedia()mithorizontal-viewport-segmentsbzw.vertical-viewport-segments. GespeicherteDOMRect-Objekte werden nicht automatisch aktualisiert. - iframes: In eingebetteten Frames liefert
segmentsnull. Nur das oberste Dokument erhält Segmentinformationen. - Zwischen zwei Segmenten kann eine Lücke liegen (die Breite des Scharniers). Berechnen Sie diese als
segments[1].x - (segments[0].x + segments[0].width)und legen Sie dort keine interaktiven Elemente ab. - Für reine Layout-Anpassungen sind die CSS-Media-Features und die Umgebungsvariablen
env(viewport-segment-*)oft einfacher und leistungsfähiger als JavaScript. Das Layout reagiert dann ohne Skript und ohne Neuberechnung. - Nicht verwechseln mit
window.visualViewport(VisualViewport). Dieses Objekt beschreibt Zoom und Bildlaufposition, nicht die physische Teilung des Bildschirms.