Bild im Bild für jedes Element, nicht nur <Video>

François Beaufort
François Beaufort

Browser Support

  • Chrome: 116.
  • Edge: 116.
  • Firefox: 151.
  • Safari: not supported.

Source

Mit der Document Picture-in-Picture API lässt sich ein Fenster öffnen, das immer im Vordergrund ist und mit beliebigem HTML-Inhalt gefüllt werden kann. Sie erweitert die vorhandene Picture-in-Picture API für <video>, mit der nur ein HTML-<video>-Element in ein BiB-Fenster (Bild im Bild) eingefügt werden kann.

Das Bild-im-Bild-Fenster in der Document Picture-in-Picture API ähnelt einem leeren Fenster mit demselben Ursprung, das mit window.open() geöffnet wird, weist jedoch einige Unterschiede auf:

  • Das Fenster für „Bild im Bild“ wird über anderen Fenstern angezeigt.
  • Das Bild-im-Bild-Fenster wird nie länger als das ursprüngliche Fenster angezeigt.
  • Das Bild-im-Bild-Fenster kann nicht bedient werden.
  • Die Position des Bild-im-Bild-Fensters kann nicht von der Website festgelegt werden.
Ein Bild-im-Bild-Fenster, in dem der Trailer für den Film „Sintel“ abgespielt wird.
Ein Bild-im-Bild-Fenster, das mit der Document Picture-in-Picture API (Demo) erstellt wurde.

Status

Schritt Status
1. Erklärung erstellen Abschließen
2. Ersten Entwurf der Spezifikation erstellen In progress
3. Feedback einholen und Design optimieren In progress
4. Ursprungstest Abschließen
5. Starten Abgeschlossen (Desktop)

Anwendungsfälle

Sie können diese API auf verschiedene Arten verwenden, z. B. für benutzerdefinierte Videoplayer, Videokonferenzen und Produktivitäts-Apps.

Benutzerdefinierter Videoplayer

Eine Website kann mit der vorhandenen Picture-in-Picture API für <video> eine Bild-im-Bild-Videowiedergabe ermöglichen. Die API ist jedoch sehr eingeschränkt. Das vorhandene BiB-Fenster akzeptiert nur wenige Eingaben und bietet nur begrenzte Möglichkeiten zum Formatieren. Wenn ein vollständiges Dokument im Bild-im-Bild-Modus angezeigt wird, kann die Website benutzerdefinierte Steuerelemente und Eingaben (z. B. Untertitel, Playlists, Zeitleiste, Liken und Disliken von Videos) bereitstellen, um die Videowiedergabe im PiP-Modus zu optimieren.

Videokonferenzsysteme

Nutzer verlassen den Browser-Tab während einer Videokonferenz häufig vorübergehend, z. B. wenn sie über einen anderen Tab präsentieren, Notizen machen oder andere Multitasking-Aktivitäten ausführen. In den meisten Fällen möchte der Nutzer den Anruf jedoch trotzdem sehen. Daher ist dies ein idealer Anwendungsfall für „Bild im Bild“. Auch hier sind die aktuellen Möglichkeiten, die eine Videokonferenzwebsite mit der Bild-im-Bild-API für <video> bietet, in Bezug auf Stil und Eingabe begrenzt. Mit einem vollständigen Dokument im Bild-im-Bild-Modus kann die Website mehrere Videostreams ganz einfach in einem einzigen BiB-Fenster kombinieren, ohne auf Canvas-Hacks angewiesen zu sein. Außerdem können benutzerdefinierte Steuerelemente wie das Senden einer Nachricht, das Stummschalten eines anderen Nutzers oder das Melden von Problemen bereitgestellt werden.

Produktivität

Untersuchungen haben ergeben, dass Nutzer mehr Möglichkeiten benötigen, um im Web produktiv zu sein. Mit der Funktion „Dokument im Bild im Bild“ können Web-Apps mehr leisten. Ob Textbearbeitung, Notizen, Aufgabenlisten, Messaging und Chat oder Design- und Entwicklungstools – Web-Apps können ihre Inhalte jetzt immer zugänglich halten.

Schnittstelle

Properties

documentPictureInPicture.window
Gibt das aktuelle „Bild im Bild“-Fenster zurück, falls vorhanden. Andernfalls wird null zurückgegeben.

Methoden

documentPictureInPicture.requestWindow(options)

Gibt ein Promise zurück, das aufgelöst wird, wenn ein Bild-im-Bild-Fenster geöffnet wird. Das Promise wird abgelehnt, wenn es ohne Nutzergeste aufgerufen wird. Das options-Wörterbuch enthält die folgenden optionalen Elemente:

width
Legt die anfängliche Breite des Fensters für „Bild im Bild“ fest.
height
Legt die anfängliche Höhe des Fensters für „Bild im Bild“ fest.
disallowReturnToOpener
Wenn „true“, wird die Schaltfläche „Zurück zum Tab“ im Bild-im-Bild-Fenster ausgeblendet. Der Standardwert ist „false“.
preferInitialWindowPlacement
Das Bild-im-Bild-Fenster wird in seiner Standardposition und ‑größe geöffnet, wenn „true“ festgelegt ist. Der Standardwert ist „false“.

Ereignisse

documentPictureInPicture.onenter
Wird bei documentPictureInPicture ausgelöst, wenn ein Bild-im-Bild-Fenster geöffnet wird.

Beispiele

Mit dem folgenden HTML-Code wird ein benutzerdefinierter Videoplayer und ein Schaltflächenelement eingerichtet, um den Videoplayer in einem Bild-im-Bild-Fenster zu öffnen.

<div id="playerContainer">
  <div id="player">
    <video id="video"></video>
  </div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>

Bild-im-Bild-Fenster öffnen

Mit dem folgenden JavaScript wird documentPictureInPicture.requestWindow() aufgerufen, wenn der Nutzer auf die Schaltfläche klickt, um ein leeres Bild-im-Bild-Fenster zu öffnen. Das zurückgegebene Promise wird mit einem JavaScript-Objekt für das Bild-im-Bild-Fenster aufgelöst. Der Videoplayer wird mit append() in dieses Fenster verschoben.

pipButton.addEventListener('click', async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

Größe des Bild-im-Bild-Fensters festlegen

Um die Größe des Bild-im-Bild-Fensters festzulegen, legen Sie die Optionen width und height von documentPictureInPicture.requestWindow() auf die ideale Größe des BiB-Fensters fest. Chrome kann die Optionswerte verringern, wenn sie zu groß oder zu klein sind, um eine benutzerfreundliche Fenstergröße zu erreichen.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window whose size is
  // the same as the player's.
  const pipWindow = await documentPictureInPicture.requestWindow({
    width: player.clientWidth,
    height: player.clientHeight,
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

Button „Zurück zum Tab“ im BiB-Fenster ausblenden

Wenn Sie den Button im Bild-im-Bild-Fenster ausblenden möchten, über den der Nutzer zum Tab mit dem Opener zurückkehren kann, legen Sie die Option disallowReturnToOpener von documentPictureInPicture.requestWindow() auf true fest.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window which hides the "back to tab" button.
  const pipWindow = await documentPictureInPicture.requestWindow({
    disallowReturnToOpener: true,
  });
});

PiP in Standardposition und ‑größe öffnen

Wenn Sie die Position oder Größe des vorherigen „Bild im Bild“-Fensters nicht wiederverwenden möchten, setzen Sie die Option preferInitialWindowPlacement von documentPictureInPicture.requestWindow() auf true.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window in its default position / size.
  const pipWindow = await documentPictureInPicture.requestWindow({
    preferInitialWindowPlacement: true,
  });
});

Stylesheets in PiP kopieren

Wenn Sie alle CSS-Stylesheets aus dem ursprünglichen Fenster kopieren möchten, durchlaufen Sie styleSheets, das explizit mit dem Dokument verknüpft oder darin eingebettet ist, und hängen Sie sie an das Bild-im-Bild-Fenster an. Beachten Sie, dass dies ein einmaliger Kopiervorgang ist.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Copy style sheets over from the initial document
  // so that the player looks the same.
  [...document.styleSheets].forEach((styleSheet) => {
    try {
      const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join('');
      const style = document.createElement('style');

      style.textContent = cssRules;
      pipWindow.document.head.appendChild(style);
    } catch (e) {
      const link = document.createElement('link');

      link.rel = 'stylesheet';
      link.type = styleSheet.type;
      link.media = styleSheet.media;
      link.href = styleSheet.href;
      pipWindow.document.head.appendChild(link);
    }
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

Umgang mit dem Schließen des BiB-Fensters

Sie können auf das Fensterereignis "pagehide" warten, um zu erfahren, wann das Bild-im-Bild-Fenster geschlossen wird (entweder weil die Website es initiiert hat oder der Nutzer es manuell geschlossen hat). Der Event-Handler ist ein guter Ort, um die Elemente wieder aus dem Bild-im-Bild-Fenster zu holen, wie hier gezeigt.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);

  // Move the player back when the Picture-in-Picture window closes.
  pipWindow.addEventListener("pagehide", (event) => {
    const playerContainer = document.querySelector("#playerContainer");
    const pipPlayer = event.target.querySelector("#player");
    playerContainer.append(pipPlayer);
  });
});

Schließen Sie das Bild-im-Bild-Fenster programmatisch mit der Methode close().

// Close the Picture-in-Picture window programmatically.
// The "pagehide" event will fire normally.
pipWindow.close();

Hören, wenn die Website in den BiB-Modus wechselt

Sie können auf documentPictureInPicture auf das "enter"-Ereignis warten, um zu erfahren, wann ein Bild-im-Bild-Fenster geöffnet wird. Das Ereignis enthält ein window-Objekt für den Zugriff auf das Bild-im-Bild-Fenster.

documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
});

Auf Elemente im BiB-Fenster zugreifen

Sie können über das von documentPictureInPicture.requestWindow() zurückgegebene Objekt oder mit documentPictureInPicture.window auf Elemente im Bild-im-Bild-Fenster zugreifen.

const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
  // Mute video playing in the Picture-in-Picture window.
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
}

Ereignisse aus dem BiB-Fenster verarbeiten

Schaltflächen und Steuerelemente erstellen und auf Nutzereingabeereignisse (z. B. "click") reagieren – wie immer in JavaScript.

// Add a "mute" button to the Picture-in-Picture window.
const pipMuteButton = pipWindow.document.createElement("button");
pipMuteButton.textContent = "Mute";
pipMuteButton.addEventListener("click", () => {
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
});
pipWindow.document.body.append(pipMuteButton);

Größe des BiB-Fensters anpassen

Verwenden Sie die Fenstermethoden resizeBy() und resizeTo(), um die Größe des Fensters für „Bild im Bild“ anzupassen. Für beide Methoden ist eine Nutzergeste erforderlich.

const resizeButton = pipWindow.document.createElement('button');
resizeButton.textContent = 'Resize';
resizeButton.addEventListener('click', () => {
  // Expand the Picture-in-Picture window's width by 20px and height by 30px.
  pipWindow.resizeBy(20, 30);
});
pipWindow.document.body.append(resizeButton);

Fokus auf das Startfenster setzen

Verwenden Sie die focus()-Fenstermethode, um das Fenster des Öffners über das Bild-im-Bild-Fenster zu fokussieren. Für diese Methode ist eine Nutzergeste erforderlich.

const returnToTabButton = pipWindow.document.createElement("button");
returnToTabButton.textContent = "Return to opener tab";
returnToTabButton.addEventListener("click", () => {
  window.focus();
});
pipWindow.document.body.append(returnToTabButton);

CSS-Anzeigemodus für Bild-im-Bild

Mit dem CSS-Anzeigemodus picture-in-picture können Sie spezifische CSS-Regeln schreiben, die nur angewendet werden, wenn (ein Teil der) Web-App im Bild-im-Bild-Modus angezeigt wird.

@media all and (display-mode: picture-in-picture) {
  body {
    margin: 0;
  }
  h1 {
    font-size: 0.8em;
  }
}

Funktionserkennung

So prüfen Sie, ob die Document Picture-in-Picture API unterstützt wird:

if ('documentPictureInPicture' in window) {
  // The Document Picture-in-Picture API is supported.
}

Demos

Tomodoro, eine Pomodoro-Web-App.
Ein Bild-im-Bild-Fenster in Tomodoro.

Feedback geben

Melden Sie Probleme auf GitHub, wenn Sie Vorschläge oder Fragen haben.