Signatur
Beschreibung
requestWindow() ist die zentrale Methode der Document Picture-in-Picture API. Anders als das klassische HTMLVideoElement.requestPictureInPicture(), das nur ein einzelnes Video schwebend anzeigen kann, öffnet sie ein eigenständiges, immer im Vordergrund liegendes Fenster mit einem leeren Document. In dieses Dokument kann man beliebige DOM-Elemente verschieben, zum Beispiel einen Videoplayer mit eigenen Bedienelementen, einen Videokonferenz-Bereich, einen Timer oder ein Notizfeld.
Die Methode erreicht man über das globale Objekt window.documentPictureInPicture. Sie gibt ein Promise zurück, das mit dem Window-Objekt des neuen Fensters erfüllt wird. Über pipWindow.document fügt man Inhalte ein, übernimmt Stylesheets und registriert Ereignisse, etwa pagehide, um Elemente beim Schließen zurück in die Hauptseite zu holen.
Wichtig: Der Aufruf erfordert eine vorübergehende Nutzeraktivierung, er muss also direkt aus einem Klick- oder Tastatur-Ereignis heraus erfolgen. Pro Haupt-Browsing-Kontext kann nur ein PiP-Fenster gleichzeitig existieren. Ein erneuter Aufruf ersetzt das vorhandene Fenster. Stylesheets der Ursprungsseite werden nicht automatisch übernommen, außer man nutzt die Option copyStyleSheets (sofern der Browser sie unterstützt) oder kopiert sie selbst.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | object | {} | Optionales Konfigurationsobjekt für das neue Fenster. |
| $options.width | number | vom Browser gewählt | Gewünschte Anfangsbreite in CSS-Pixeln. Wird nur zusammen mit height berücksichtigt und kann vom Browser begrenzt werden. |
| $options.height | number | vom Browser gewählt | Gewünschte Anfangshöhe in CSS-Pixeln. Wird nur zusammen mit width berücksichtigt. |
| $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 in Standardgröße und -position, statt sich an eine zuvor vom Nutzer gewählte Größe oder Position zu erinnern (Chrome 130+). |
Rückgabewert
Promise, das mit dem Window-Objekt des geöffneten Picture-in-Picture-Fensters erfüllt wird. Es wird mit einer DOMException abgelehnt, zum Beispiel NotAllowedError ohne Nutzeraktivierung oder NotSupportedError in nicht unterstützten Kontexten.Beispiele
Videoplayer in ein PiP-Fenster verschieben
const player = document.querySelector('#player');
const container = document.querySelector('#player-container');
document.querySelector('#pip-btn').addEventListener('click', async () => {
if (!('documentPictureInPicture' in window)) {
console.warn('Document Picture-in-Picture wird nicht unterstützt');
return;
}
const pipWindow = await documentPictureInPicture.requestWindow({
width: player.clientWidth,
height: player.clientHeight,
});
// Element verschieben (nicht kopieren)
pipWindow.document.body.append(player);
// Beim Schließen zurück in die Hauptseite holen
pipWindow.addEventListener('pagehide', () => {
container.append(player);
});
});
Stylesheets der Hauptseite übernehmen
const copyStyles = (pipWindow) => {
[...document.styleSheets].forEach((sheet) => {
try {
const css = [...sheet.cssRules].map((r) => r.cssText).join('');
const style = pipWindow.document.createElement('style');
style.textContent = css;
pipWindow.document.head.append(style);
} catch {
// Fremd-Ursprung-Stylesheet: per <link> einbinden
const link = pipWindow.document.createElement('link');
link.rel = 'stylesheet';
link.href = sheet.href;
pipWindow.document.head.append(link);
}
});
};
document.querySelector('#timer-pip').addEventListener('click', async () => {
const pipWindow = await documentPictureInPicture.requestWindow({ width: 300, height: 120 });
copyStyles(pipWindow);
pipWindow.document.body.append(document.querySelector('#timer'));
});
Fehlerbehandlung und vorhandenes Fenster prüfen
const openPip = async () => {
// Bereits geöffnetes Fenster wiederverwenden
if (documentPictureInPicture.window) {
documentPictureInPicture.window.focus();
return documentPictureInPicture.window;
}
try {
return await documentPictureInPicture.requestWindow({ disallowReturnToOpener: true });
} catch (err) {
console.error(`${err.name}: ${err.message}`);
}
};
// Ohne Nutzeraktivierung schlägt der Aufruf fehl:
openPip();
// Wichtig · Fallstricke
- Browser-Unterstützung: Bisher nur in Chromium-basierten Desktop-Browsern (Chrome/Edge ab 116). Firefox und Safari unterstützen die API nicht, ebenso wenig mobile Browser. Verfügbarkeit daher immer mit
'documentPictureInPicture' in windowprüfen. - Nur in sicheren Kontexten (HTTPS) und nur im obersten Browsing-Kontext. Aus einem iframe oder einem PiP-Fenster selbst heraus schlägt der Aufruf fehl.
- Nutzeraktivierung erforderlich: Ohne vorausgehende Nutzerinteraktion wird das Promise mit
NotAllowedErrorabgelehnt. Nach einemawaitkann die Aktivierung bereits verbraucht sein. DeshalbrequestWindow()möglichst früh im Handler aufrufen. widthundheightmüssen gemeinsam angegeben werden. Wird nur einer der beiden Werte gesetzt, gibt es einenRangeError.- Das PiP-Fenster lässt sich nicht per Skript navigieren, und
window.open()ist dort nicht möglich. Die Fenstergröße lässt sich mitresizeTo()/resizeBy()nur nach einer Nutzeraktivierung ändern. - Verschobene Elemente behalten ihre Ereignis-Listener. Ein
<video>-Element kann beim Verschieben aber kurz stocken. Die Elemente am besten beimpagehide-Ereignis zurückverschieben, sonst gehen sie mit dem Fenster verloren.