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

François Beaufort
François Beaufort

Browser Support

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

Source

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

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, es gibt jedoch einige Unterschiede:

  • 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 zu „Sintel“ abgespielt wird.
Ein Bild-im-Bild-Fenster, das mit der Document Picture-in-Picture API erstellt wurde (Demo).

Status

Schritt Status
1. Erklärung erstellen Abschließen
2. Ersten Entwurf der Spezifikation erstellen In progress
3. Feedback einholen und Design iterieren 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 anbieten, diese 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 BiB-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 Möglichkeiten, die eine Videokonferenzwebsite mit der Bild-im-Bild-API für <video> bieten kann, 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 es sich um Textbearbeitung, Notizen, Aufgabenlisten, Messaging und Chat oder Design- und Entwicklungstools handelt – Web-Apps können ihre Inhalte jetzt immer zugänglich halten.

Schnittstelle

Attribute

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 Nutzeraktion 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“ festgelegt ist, 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 der 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

Legen Sie die Größe des BiB-Fensters fest, indem Sie die Optionen width und height von documentPictureInPicture.requestWindow() auf die ideale Größe des BiB-Fensters einstellen. Chrome kann die Optionswerte reduzieren, wenn sie zu groß oder zu klein sind, um in ein benutzerfreundliches Fenster zu passen.

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);
});

Schaltfläche „Zurück zum Tab“ im BiB-Fenster ausblenden

Wenn Sie die Schaltfläche im Bild-im-Bild-Fenster ausblenden möchten, über die 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

Um alle CSS-Stylesheets aus dem ursprünglichen Fenster zu kopieren, durchlaufen Sie styleSheets, die explizit mit dem Dokument verknüpft oder darin eingebettet sind, und hängen Sie sie an das Bild-im-Bild-Fenster an. Beachten Sie, dass es sich um ein einmaliges Kopieren handelt.

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 "pagehide"-Ereignis des Fensters 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 werden wie immer in JavaScript erstellt und auf Nutzereingabeereignisse wie "click" wird reagiert.

// 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 Nutzeraktion 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 Fenster zum Öffnen setzen

Verwenden Sie die focus()-Methode „Window“, um das Fenster des Öffners über das Bild-im-Bild-Fenster zu fokussieren. Für diese Methode ist eine Nutzeraktion 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.