Verwendung der Document Picture-in-Picture API

Experimentell: Dies ist eine experimentelle Technologie
Überprüfen Sie die Browser-Kompatibilitätstabelle sorgfältig vor der Verwendung auf produktiven Webseiten.

Sicherer Kontext: Diese Funktion ist nur in sicheren Kontexten (HTTPS) in einigen oder allen unterstützenden Browsern verfügbar.

Dieser Leitfaden bietet eine Anleitung zur typischen Nutzung der Document Picture-in-Picture API.

Hinweis: Sie können das vorgestellte Demo in Aktion sehen unter Document Picture-in-Picture API Example (sehen Sie sich auch den vollständigen Quellcode an).

Beispiel-HTML

Das folgende HTML richtet einen grundlegenden Videoplayer ein.

html
<div id="container">
  <p class="in-pip-message">
    Video player is currently in the separate Picture-in-Picture window.
  </p>
  <div id="player">
    <video
      src="assets/bigbuckbunny.mp4"
      id="video"
      controls
      width="320"></video>

    <div id="credits">
      <a href="https://peach.blender.org/download/" target="_blank">
        Video by Blender </a
      >;
      <a href="https://peach.blender.org/about/" target="_blank">
        licensed CC-BY 3.0
      </a>
    </div>

    <div id="control-bar">
      <p class="no-picture-in-picture">
        Document Picture-in-Picture API not available
      </p>

      <p></p>
    </div>
  </div>
</div>

Funktionsüberprüfung

Um zu prüfen, ob die Document Picture-in-Picture API unterstützt wird, können Sie testen, ob documentPictureInPicture auf window verfügbar ist:

js
if ("documentPictureInPicture" in window) {
  document.querySelector(".no-picture-in-picture").remove();

  const togglePipButton = document.createElement("button");
  togglePipButton.textContent = "Toggle Picture-in-Picture";
  togglePipButton.addEventListener("click", togglePictureInPicture, false);

  document.getElementById("control-bar").appendChild(togglePipButton);
}

Ist es verfügbar, entfernen wir die Nachricht "Document Picture-in-Picture API not available" und fügen stattdessen ein <button>-Element hinzu, um den Videoplayer in einem Document Picture-in-Picture-Fenster zu öffnen.

Öffnen eines Picture-in-Picture Fensters

Das folgende JavaScript ruft window.documentPictureInPicture.requestWindow() auf, um ein leeres Picture-in-Picture-Fenster zu öffnen. Das zurückgegebene Promise erfüllt sich mit einem Picture-in-Picture Window Objekt. Der Videoplayer wird in dieses Fenster verschoben, indem Element.append() verwendet wird, und wir zeigen die Nachricht an, die den Benutzer informiert, dass er verschoben wurde.

Die Optionen width und height von requestWindow() setzen das Picture-in-Picture-Fenster auf die gewünschte Größe. Browser können die Optionswerte anpassen, wenn sie zu groß oder zu klein für eine benutzerfreundliche Fenstergröße sind.

js
async function togglePictureInPicture() {
  // Early return if there's already a Picture-in-Picture window open
  if (window.documentPictureInPicture.window) {
    return;
  }

  // Open a Picture-in-Picture window.
  const pipWindow = await window.documentPictureInPicture.requestWindow({
    width: videoPlayer.clientWidth,
    height: videoPlayer.clientHeight,
  });

  // ...

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

  // Display a message to say it has been moved
  inPipMessage.style.display = "block";
}

Stilvorlagen in das Picture-in-Picture Fenster kopieren

Um alle CSS-Stilvorlagen aus dem ursprünglichen Fenster zu kopieren, durchlaufen Sie alle Stilvorlagen, die explizit in das Dokument verlinkt oder eingebettet sind (über Document.styleSheets), und hängen Sie sie an das Picture-in-Picture-Fenster an. Beachten Sie, dass dies eine einmalige Kopie ist.

js
// ...

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

// ...

Stile im Picture-in-Picture Modus anpassen

Der picture-in-picture Wert der display-mode Media-Feature ermöglicht es Entwicklern, CSS auf ein Dokument anzuwenden, je nachdem, ob es im Picture-in-Picture-Modus angezeigt wird. Die grundlegende Anwendung sieht so aus:

css
@media (display-mode: picture-in-picture) {
  body {
    background: red;
  }
}

Dieses Snippet macht den Hintergrund des Dokuments <body> rot, nur wenn es im Picture-in-Picture-Modus angezeigt wird.

In unserem Demo kombinieren wir den display-mode: picture-in-picture Wert mit dem prefers-color-scheme Media-Feature, um helle und dunkle Farbschemas zu erzeugen, die basierend auf der Farbpräferenz des Benutzers angewendet werden, nur wenn die App im Picture-in-Picture-Modus angezeigt wird.

css
@media (display-mode: picture-in-picture) and (prefers-color-scheme: light) {
  body {
    background: antiquewhite;
  }
}

@media (display-mode: picture-in-picture) and (prefers-color-scheme: dark) {
  body {
    background: #333;
  }

  a {
    color: antiquewhite;
  }
}

Umgang mit dem Schließen des Picture-in-Picture Fensters

Der Code zum erneuten Schließen des Picture-in-Picture Fensters, wenn der Button ein zweites Mal gedrückt wird, sieht wie folgt aus:

js
inPipMessage.style.display = "none";
playerContainer.append(videoPlayer);
window.documentPictureInPicture.window.close();

Hier kehren wir die DOM-Änderungen um — wir blenden die Nachricht aus und setzen den Videoplayer wieder in den Player-Container im Hauptanwendungsfenster. Wir schließen auch das Picture-in-Picture-Fenster programmatisch mit der Window.close() Methode.

Sie müssen jedoch auch den Fall berücksichtigen, dass der Benutzer das Picture-in-Picture-Fenster schließt, indem er den vom Browser bereitgestellten Schließen (X) Knopf im Fenster selbst drückt. Dies können Sie behandeln, indem Sie feststellen, wann das Fenster geschlossen wird, indem Sie das pagehide Ereignis erkennen:

js
pipWindow.addEventListener("pagehide", (event) => {
  inPipMessage.style.display = "none";
  playerContainer.append(videoPlayer);
});

Zuhören, wann die Website in Picture-in-Picture wechselt

Hören Sie auf das enter Ereignis auf der DocumentPictureInPicture Instanz, um zu wissen, wann ein Picture-in-Picture-Fenster geöffnet wird.

In unserem Demo verwenden wir das enter Ereignis, um einen Stummschaltknopf zum Picture-in-Picture-Fenster hinzuzufügen:

js
documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
  console.log("Video player has entered the pip window");

  const pipMuteButton = pipWindow.document.createElement("button");
  pipMuteButton.textContent = "Mute";
  pipMuteButton.addEventListener("click", () => {
    const pipVideo = pipWindow.document.querySelector("#video");
    if (!pipVideo.muted) {
      pipVideo.muted = true;
      pipMuteButton.textContent = "Unmute";
    } else {
      pipVideo.muted = false;
      pipMuteButton.textContent = "Mute";
    }
  });

  pipWindow.document.body.append(pipMuteButton);
});

Hinweis: Das DocumentPictureInPictureEvent Ereignisobjekt enthält eine window Eigenschaft, um auf das Picture-in-Picture-Fenster zuzugreifen.

Zugriff auf Elemente und Umgang mit Ereignissen

Sie können auf Elemente im Picture-in-Picture-Fenster auf verschiedene Weise zugreifen:

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

Sobald Sie eine Referenz zur Picture-in-Picture window Instanz haben, können Sie den DOM manipulieren (z.B. Buttons erstellen) und auf Benutzereingabeereignisse (wie click) reagieren, wie Sie es normalerweise im regulären Browserfensterkontext tun würden.