Picture-in-Picture voor elk element, niet alleen <video>

François Beaufort
François Beaufort

Browser Support

  • Chroom: 116.
  • Rand: 116.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Source

De Document Picture-in-Picture API maakt het mogelijk om een altijd-bovenaan venster te openen dat kan worden gevuld met willekeurige HTML-inhoud. Het is een uitbreiding van de bestaande Picture-in-Picture API voor <video> , die alleen het plaatsen van een HTML <video> -element in een Picture-in-Picture-venster toestaat.

Het Picture-in-Picture-venster in de Document Picture-in-Picture API is vergelijkbaar met een leeg venster met dezelfde oorsprong dat wordt geopend via window.open() , met enkele verschillen:

  • Het Picture-in-Picture-venster zweeft bovenop andere vensters.
  • Het Picture-in-Picture-venster overleeft het openingsvenster nooit.
  • Er kan niet door het Picture-in-Picture-venster worden genavigeerd.
  • De positie van het Picture-in-Picture-venster kan niet door de website worden ingesteld.
Een Picture-in-Picture-venster waarin de trailervideo van Sintel wordt afgespeeld.
Een Picture-in-Picture-venster gemaakt met de Document Picture-in-Picture API ( demo ).

Huidige status

Stap Status
1. Maak een uitleg Compleet
2. Maak een eerste ontwerp van de specificatie In uitvoering
3. Verzamel feedback en herhaal het ontwerp In uitvoering
4. Oorsprongsproef Compleet
5. Lancering Compleet (Bureaublad)

Gebruiksscenario's

Aangepaste videospeler

Een website kan een Picture-in-Picture-video-ervaring bieden met de bestaande Picture-in-Picture API voor <video> , maar deze is zeer beperkt. Het bestaande Picture-in-Picture-venster accepteert weinig invoer en heeft beperkte mogelijkheden voor de styling ervan. Met een volledig document in Picture-in-Picture kan de website aangepaste bedieningselementen en invoer bieden (bijvoorbeeld ondertitels , afspeellijsten, een tijdscrubber, het leuk vinden en niet leuk vinden van video's) om de Picture-in-Picture-video-ervaring van de gebruiker te verbeteren.

Videoconferenties

Het komt vaak voor dat gebruikers tijdens een videoconferentiesessie om verschillende redenen het browsertabblad verlaten (bijvoorbeeld om een ander tabblad aan het gesprek te presenteren of om te multitasken), terwijl ze het gesprek toch willen zien. Dit is dan ook een uitstekende use case voor Picture-in-Picture. Nogmaals, de huidige ervaring die een videoconferentiewebsite kan bieden via de Picture-in-Picture API voor <video> is beperkt in stijl en invoer. Met een volledig Document in Picture-in-Picture kan de website eenvoudig meerdere videostreams combineren in één PiP-venster zonder dat er canvas-hacks nodig zijn en zonder aangepaste bedieningselementen zoals het verzenden van een bericht, het dempen van een andere gebruiker of het opsteken van een hand.

Productiviteit

Onderzoek heeft aangetoond dat gebruikers meer mogelijkheden nodig hebben om productief te zijn op het web. Document in Picture-in-Picture geeft webapps de flexibiliteit om meer te bereiken. Of het nu gaat om tekstbewerking, notities maken, takenlijsten, berichten en chatten, of ontwerp- en ontwikkeltools, webapps kunnen hun content nu altijd toegankelijk houden.

Interface

Eigenschappen

documentPictureInPicture.window
Retourneert het huidige Picture-in-Picture-venster (indien aanwezig). Anders wordt null geretourneerd.

Methoden

documentPictureInPicture.requestWindow(options)

Retourneert een belofte die wordt opgelost wanneer een Picture-in-Picture-venster wordt geopend. De belofte wordt afgewezen als deze wordt aangeroepen zonder een gebruikersgebaar. Het options bevat de volgende optionele leden:

width
Stelt de beginbreedte van het Picture-in-Picture-venster in.
height
Stelt de beginhoogte van het Picture-in-Picture-venster in.
disallowReturnToOpener
Verbergt de knop 'Terug naar tabblad' in het Picture-in-Picture-venster indien 'true'. Standaard is dit 'false'.
preferInitialWindowPlacement
Open het Picture-in-Picture-venster in de standaardpositie en -grootte als 'true' is ingeschakeld. Standaard is dit 'false'.

Evenementen

documentPictureInPicture.onenter
Wordt geactiveerd op documentPictureInPicture wanneer een Picture-in-Picture-venster wordt geopend.

Voorbeelden

Met de volgende HTML-code worden een aangepaste videospeler en een knopelement ingesteld om de videospeler te openen in een Picture-in-Picture-venster.

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

Open een Picture-in-Picture-venster

De volgende JavaScript-code roept documentPictureInPicture.requestWindow() aan wanneer de gebruiker op de knop klikt om een leeg Picture-in-Picture-venster te openen. De geretourneerde promise wordt omgezet naar een Picture-in-Picture-venster JavaScript-object. De videospeler wordt naar dat venster verplaatst met append() .

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

De grootte van het Picture-in-Picture-venster instellen

Om de grootte van het Picture-in-Picture-venster in te stellen, stelt u de width en height van documentPictureInPicture.requestWindow() in op de gewenste Picture-in-Picture-venstergrootte. Chrome kan de optiewaarden beperken als ze te groot of te klein zijn voor een gebruiksvriendelijk vensterformaat.

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

Verberg de knop 'Terug naar tabblad' van het Picture-in-Picture-venster

Om de knop in het Picture-in-Picture-venster te verbergen waarmee de gebruiker kan teruggaan naar het tabblad van de opener, stelt u de optie disallowReturnToOpener van documentPictureInPicture.requestWindow() in op true .

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

Open het Picture-in-Picture-venster in de standaardpositie en -grootte

Als u de positie of grootte van het vorige Picture-in-Picture-venster niet opnieuw wilt gebruiken, stelt u de optie preferInitialWindowPlacement van documentPictureInPicture.requestWindow() in op true .

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

Stijlbladen kopiëren naar het Picture-in-Picture-venster

Om alle CSS-stijlbladen uit het oorspronkelijke venster te kopiëren, doorloopt u styleSheets die expliciet aan het document zijn gekoppeld of erin zijn ingesloten en voegt u ze toe aan het Picture-in-Picture-venster. Let op: dit is een eenmalige kopie.

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

Handgreep wanneer het Picture-in-Picture-venster sluit

Luister naar de "pagehide" -gebeurtenis van het venster om te weten wanneer het Picture-in-Picture-venster wordt gesloten (omdat de website het heeft geïnitieerd of de gebruiker het handmatig heeft gesloten). De gebeurtenishandler is een goede manier om de elementen weer uit het Picture-in-Picture-venster te halen, zoals hier wordt getoond.

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

Sluit het Picture-in-Picture-venster programmatisch met behulp van de close() methode.

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

Luister wanneer de website Picture-in-Picture invoert

Luister naar de "enter" -gebeurtenis op documentPictureInPicture om te weten wanneer een Picture-in-Picture-venster wordt geopend. De gebeurtenis bevat een window om toegang te krijgen tot het Picture-in-Picture-venster.

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

Toegang tot elementen in het Picture-in-Picture-venster

U kunt toegang krijgen tot elementen in het Picture-in-Picture-venster via het object dat wordt geretourneerd door documentPictureInPicture.requestWindow() of met documentPictureInPicture.window , zoals hieronder wordt weergegeven.

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

Gebeurtenissen verwerken vanuit het Picture-in-Picture-venster

Maak knoppen en besturingselementen en reageer op invoergebeurtenissen van de gebruiker, zoals "click" , zoals u dat normaal gesproken in JavaScript zou doen.

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

Het formaat van het Picture-in-Picture-venster wijzigen

Gebruik de venstermethoden resizeBy() en resizeTo() om het formaat van het Picture-in-Picture-venster aan te passen. Beide methoden vereisen een gebruikersgebaar.

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

Focus het openervenster

Gebruik de focus() Window-methode om het geopende venster te focussen vanuit het Picture-in-Picture-venster. Deze methode vereist een gebruikersgebaar.

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

CSS-beeld-in-beeld-weergavemodus

Gebruik de picture-in-picture weergavemodus van CSS om specifieke CSS-regels te schrijven die alleen worden toegepast wanneer (een deel van) de web-app wordt weergegeven in de Picture-in-Picture-modus.

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

Functiedetectie

Om te controleren of de Document Picture-in-Picture API wordt ondersteund, gebruikt u:

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

Demo's

VideoJS-speler

U kunt spelen met de Document Picture-in-Picture API VideoJS-spelerdemo .

Pomodoro

Tomodoro , een Pomodoro-webapp, maakt ook gebruik van de Document Picture-in-Picture API zodra deze beschikbaar is. Zie hun GitHub pull request .

Tomodoro, een pomodoro-webapp.
Een Picture-in-Picture-venster in Tomodoro.

Deel uw feedback

Meld problemen op GitHub met suggesties en vragen.