Signatur
Beschreibung
Das Interface DocumentPictureInPicture gehört zur Document Picture-in-Picture API. Die Instanz erreicht man über window.documentPictureInPicture. Anders als das klassische Bild-im-Bild für <video> (HTMLVideoElement.requestPictureInPicture()) kann man damit ein komplettes Dokument in einem schwebenden Fenster anzeigen, das immer im Vordergrund bleibt. Darin können beliebige DOM-Elemente stehen, etwa ein Videoplayer mit eigenen Bedienelementen, eine Videokonferenz-Kachel, ein Timer oder ein Notizblock.
Das Interface bietet:
requestWindow(options): öffnet das PiP-Fenster und gibt einPromise<Window>zurück. DasWindow-Objekt ist anfangs leer (about:blank, gleicher Ursprung wie der Öffner).window(nur lesbar): das aktuell geöffnete PiP-Windowodernull.- Event
enter: wird ausgelöst, sobald das PiP-Fenster geöffnet ist (DocumentPictureInPictureEventmit Eigenschaftwindow). Registrieren lässt es sich überaddEventListener("enter", …)oderonenter.
Üblicherweise verschiebt man vorhandene DOM-Knoten mit append() ins PiP-Fenster. Sie behalten dabei ihren Zustand, ein laufendes Video spielt also weiter. Wird das Fenster geschlossen, holt man sie im Event pagehide des PiP-Fensters wieder zurück. Stylesheets werden nicht automatisch übernommen, die muss man selbst ins neue Dokument kopieren.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options.width | number | vom Browser gewählt | Gewünschte Anfangsbreite des PiP-Fensters in CSS-Pixeln. Der Browser kann den Wert begrenzen. Wenn angegeben, muss auch height gesetzt werden. |
| $options.height | number | vom Browser gewählt | Gewünschte Anfangshöhe in CSS-Pixeln. Wenn angegeben, muss auch width gesetzt werden. |
| $options.disallowReturnToOpener | boolean | false | Bei true blendet der Browser die Schaltfläche „Zurück zum Tab“ im PiP-Fenster aus. |
| $options.preferInitialWindowPlacement | boolean | false | Bei true öffnet sich das Fenster mit Standardgröße und -position, statt sich an eine frühere Größe oder Position zu erinnern (Chrome 130+). |
Beispiele
Videoplayer ins PiP-Fenster verschieben und zurückholen
const pipButton = document.querySelector('#pip-button');
const player = document.querySelector('#player');
const playerContainer = document.querySelector('#player-container');
pipButton.addEventListener('click', async () => {
if (!('documentPictureInPicture' in window)) {
console.warn('Document Picture-in-Picture wird nicht unterstützt.');
return;
}
// Muss direkt in einem Klick-Handler laufen (Nutzeraktivierung)
const pipWindow = await documentPictureInPicture.requestWindow({
width: 480,
height: 270,
});
// Element verschieben – das Video läuft weiter
pipWindow.document.body.append(player);
// Beim Schließen wieder ins Hauptdokument zurückholen
pipWindow.addEventListener('pagehide', () => {
playerContainer.append(player);
});
});
Stylesheets ins PiP-Dokument kopieren
const copyStyles = (pipWindow) => {
for (const sheet of document.styleSheets) {
try {
// Gleicher Ursprung: Regeln direkt übernehmen
const css = [...sheet.cssRules].map((rule) => rule.cssText).join('\n');
const style = pipWindow.document.createElement('style');
style.textContent = css;
pipWindow.document.head.append(style);
} catch {
// Fremder Ursprung: per <link> einbinden
const link = pipWindow.document.createElement('link');
link.rel = 'stylesheet';
link.href = sheet.href;
pipWindow.document.head.append(link);
}
}
};
document.querySelector('#open-timer').addEventListener('click', async () => {
const pipWindow = await documentPictureInPicture.requestWindow();
copyStyles(pipWindow);
pipWindow.document.body.innerHTML = '<p class="timer">00:00</p>';
});
Auf das enter-Event reagieren und den Zustand prüfen
documentPictureInPicture.addEventListener('enter', (event) => {
const pipWindow = event.window;
console.log('PiP geöffnet:', pipWindow.innerWidth, 'x', pipWindow.innerHeight);
});
// Alternativ über die on-Property:
// documentPictureInPicture.onenter = (event) => { ... };
const closePip = () => {
// window ist null, wenn kein PiP-Fenster offen ist
documentPictureInPicture.window?.close();
};
document.querySelector('#close-pip').addEventListener('click', closePip);
// Wichtig · Fallstricke
- Browser-Unterstützung: Bisher gibt es die API nur in Chromium-Browsern auf dem Desktop (Chrome/Edge 116+). Firefox, Safari und mobile Browser unterstützen sie nicht, daher immer per
'documentPictureInPicture' in windowprüfen und eine Alternative anbieten. - Sicherer Kontext: Die API funktioniert nur über HTTPS bzw.
localhost. - Nutzeraktivierung erforderlich:
requestWindow()klappt nur direkt nach einer Nutzeraktion wie einem Klick. Sonst gibt es einenNotAllowedError. - Pro Tab kann nur ein PiP-Fenster offen sein. Ein weiterer Aufruf schließt das bestehende Fenster. Aus einem iframe oder aus dem PiP-Fenster selbst lässt sich kein PiP-Fenster öffnen.
- Das PiP-Fenster lässt sich nicht per Skript an eine andere Stelle verschieben oder auf andere Adressen navigieren.
resizeTo()/resizeBy()funktionieren nur nach einer Nutzeraktion im PiP-Fenster. - CSS wird nicht vererbt, Stylesheets müssen kopiert werden. Event-Listener an verschobenen Elementen bleiben erhalten. Code, der mit dem globalen
documentarbeitet, bezieht sich aber weiterhin auf das Hauptdokument, verwende dortelement.ownerDocument. - Mit der Media-Query
@media all and (display-mode: picture-in-picture)lassen sich Stile speziell für das PiP-Fenster schreiben.