Picture in picture per qualsiasi elemento, non solo per i <video>

François Beaufort
François Beaufort

Browser Support

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

Source

L'API Document Picture-in-Picture consente di aprire una finestra sempre in primo piano che può essere riempita con contenuti HTML arbitrari. Estende l'API Picture-in-Picture esistente per <video> che consente di inserire un elemento HTML <video> in una finestra Picture-in-Picture (PiP).

La finestra Picture-in-Picture nell'API Document Picture-in-Picture è simile a una finestra vuota della stessa origine aperta utilizzando window.open(), con alcune differenze:

  • La finestra Picture-in-Picture è mobile e si trova sopra le altre finestre.
  • La finestra Picture-in-Picture non sopravvive mai alla finestra di apertura.
  • Non è possibile navigare nella finestra Picture-in-Picture.
  • La posizione della finestra Picture-in-Picture non può essere impostata dal sito web.
Una finestra Picture in picture che riproduce il trailer di Sintel.
Una finestra Picture-in-Picture creata con l'API Document Picture-in-Picture (demo).

Stato

Passaggio Stato
1. Crea una spiegazione Completato
2. Crea la bozza iniziale delle specifiche In corso
3. Raccogli feedback e itera sul design In corso
4. Prova dell'origine Completato
5. Avvia Completato (computer)

Casi d'uso

Puoi utilizzare questa API in diversi modi, tra cui video player personalizzati, videoconferenze e app per la produttività.

Video player personalizzato

Un sito web può fornire un'esperienza video Picture-in-Picture con l'API Picture-in-Picture esistente per <video>, ma è molto limitata. La finestra PiP esistente accetta pochi input e ha una capacità limitata di applicare stili. Con un documento completo in Picture-in-Picture, il sito web può fornire controlli e input personalizzati (ad esempio, sottotitoli, playlist, barra di scorrimento temporale, Mi piace e Non mi piace dei video) per migliorare l'esperienza video PiP dell'utente.

Videoconferenze

Spesso gli utenti abbandonano temporaneamente la scheda del browser durante una sessione di videoconferenza, ad esempio quando presentano da un'altra scheda alla chiamata, prendono appunti o svolgono altre attività di multitasking. Tuttavia, nella maggior parte dei casi, l'utente vuole comunque vedere la chiamata, quindi questo è un caso d'uso ideale per Picture-in-Picture. Ancora una volta, l'esperienza attuale che un sito web di videoconferenza può fornire con l'API Picture-in-Picture per <video> è limitata in termini di stile e input. Con un documento completo in Picture-in-Picture, il sito web può combinare facilmente più stream video in un'unica finestra PiP, senza ricorrere a hack di canvas, e fornire controlli personalizzati, ad esempio inviare un messaggio, disattivare l'audio di un altro utente o alzare la mano.

Produttività

Le ricerche hanno dimostrato che gli utenti hanno bisogno di più modi per essere produttivi sul web. Document in Picture-in-Picture offre alle app web la flessibilità di fare di più. Che si tratti di editing di testo, presa di appunti, elenchi di attività, messaggistica e chat o strumenti di progettazione e sviluppo, le app web possono ora mantenere i loro contenuti sempre accessibili.

Interfaccia

Proprietà

documentPictureInPicture.window
Restituisce la finestra Picture-in-Picture corrente, se presente. In caso contrario, restituisce null.

Metodi

documentPictureInPicture.requestWindow(options)

Restituisce una promessa che viene risolta quando viene aperta una finestra Picture-in-Picture. La promessa viene rifiutata se viene chiamata senza un'attivazione dall'utente. Il dizionario options contiene i seguenti membri facoltativi:

width
Imposta la larghezza iniziale della finestra Picture-in-Picture.
height
Imposta l'altezza iniziale della finestra Picture-in-Picture.
disallowReturnToOpener
Se è true, nasconde il pulsante "Torna alla scheda" nella finestra Picture-in-Picture. Il valore predefinito è false.
preferInitialWindowPlacement
Se è true, apre la finestra Picture-in-Picture nella posizione e nelle dimensioni predefinite. Il valore predefinito è false.

Eventi

documentPictureInPicture.onenter
Viene attivato su documentPictureInPicture quando viene aperta una finestra Picture-in-Picture.

Esempi

Il seguente codice HTML configura un video player personalizzato e un elemento pulsante per aprire il video player in una finestra Picture-in-Picture.

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

Aprire una finestra Picture-in-Picture

Il seguente codice JavaScript chiama documentPictureInPicture.requestWindow() quando l'utente fa clic sul pulsante per aprire una finestra Picture-in-Picture vuota. La promessa restituita viene risolta con un oggetto JavaScript della finestra Picture-in-Picture. Il video player viene spostato in quella finestra utilizzando 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);
});

Impostare le dimensioni della finestra Picture-in-Picture

Per impostare le dimensioni della finestra Picture-in-Picture, imposta le opzioni width e height di documentPictureInPicture.requestWindow() sulle dimensioni ideali della finestra PiP. Chrome potrebbe ridurre i valori delle opzioni se sono troppo grandi o troppo piccoli per adattarsi a una dimensione della finestra di facile utilizzo.

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

Nascondere il pulsante "Torna alla scheda" nella finestra PiP

Per nascondere il pulsante nella finestra Picture-in-Picture che consente all'utente di tornare alla scheda di apertura, imposta l'opzione disallowReturnToOpener di documentPictureInPicture.requestWindow() su 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,
  });
});

Aprire PiP nella posizione e nelle dimensioni predefinite

Per non riutilizzare la posizione o le dimensioni della finestra Picture-in-Picture precedente, imposta l'opzione preferInitialWindowPlacement di documentPictureInPicture.requestWindow() su true.

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

Copiare i fogli di stile in PiP

Per copiare tutti i fogli di stile CSS dalla finestra di origine, scorri i styleSheets collegati o incorporati esplicitamente nel documento e aggiungili alla finestra Picture-in-Picture. Tieni presente che si tratta di una copia una tantum.

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

Gestire la chiusura della finestra PiP

Ascolta l'evento "pagehide" della finestra per sapere quando la finestra Picture-in-Picture viene chiusa (perché è stata avviata dal sito web o perché l'utente l'ha chiusa manualmente). Il gestore di eventi è un buon punto per recuperare gli elementi dalla finestra Picture-in-Picture, come mostrato qui.

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

Chiudi la finestra Picture-in-Picture a livello di programmazione utilizzando il metodo close().

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

Ascoltare quando il sito web entra in PiP

Ascolta l'evento "enter" su documentPictureInPicture per sapere quando viene aperta una finestra Picture-in-Picture. L'evento contiene un oggetto window per accedere alla finestra Picture-in-Picture.

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

Accedere agli elementi nella finestra PiP

Accedi agli elementi nella finestra Picture-in-Picture dall'oggetto restituito da documentPictureInPicture.requestWindow() o con documentPictureInPicture.window.

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

Gestire gli eventi dalla finestra PiP

Crea pulsanti e controlli e rispondi agli eventi di input dell'utente (ad esempio "click"), come sempre 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);

Ridimensionare la finestra PiP

Utilizza i metodi Window resizeBy() e resizeTo() per ridimensionare la finestra Picture-in-Picture. Entrambi i metodi richiedono un gesto dell'utente.

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

Impostare lo stato attivo sulla finestra di apertura

Utilizza il metodo focus() Window per impostare lo stato attivo sulla finestra di apertura dalla finestra Picture-in-Picture. Questo metodo richiede un gesto dell'utente.

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

Modalità di visualizzazione PiP CSS

Utilizza la modalità di visualizzazione CSS picture-in-picture per scrivere regole CSS specifiche che vengono applicate solo quando (parte dell')app web viene visualizzata in modalità Picture-in-Picture.

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

Rilevamento delle funzionalità

Per verificare se l'API Document Picture-in-Picture è supportata, utilizza:

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

Demo

Tomodoro, un&#39;app web Pomodoro.
Una finestra Picture-in-Picture in Tomodoro.

Condividere il feedback

Invia segnalazioni su GitHub con suggerimenti e domande.