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

François Beaufort
François Beaufort

Supporto dei browser

  • 116
  • 116
  • x
  • x

Fonte

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

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

  • La finestra Picture in picture è sospesa sopra altre finestre.
  • La finestra Picture in picture non supera mai la finestra che si apre.
  • Impossibile 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 video trailer di Sintel.
Una finestra Picture in picture creata con l'API Document Picture-in-Picture (demo).

Stato attuale

Passaggio Stato
1. Crea messaggio esplicativo Completato
2. Crea una bozza iniziale della specifica In corso
3. Raccogli feedback e ottimizza il design In corso
4. Prova dell'origine Completato
5. Avvia Completato (computer)

casi d'uso

Video player personalizzato

Un sito web può fornire un'esperienza video Picture in picture con l'API Picture in picture per <video> esistente, ma è molto limitata. La finestra Picture in picture esistente accetta pochi input e ha una capacità limitata di applicarne uno stile. Con un documento completo in Picture in picture, il sito web può fornire controlli e input personalizzati (ad esempio, sottotitoli codificati, playlist, cursore del tempo, Mi piace e Non mi piace sui video) per migliorare l'esperienza video Picture in picture dell'utente.

Videoconferenze

È frequente che gli utenti abbandonino la scheda del browser durante una sessione di videoconferenza per vari motivi (ad esempio, perché hanno presentato un'altra scheda durante la chiamata o si svolgono attività in multitasking) mentre desiderano vedere la chiamata, pertanto si tratta di un caso d'uso fondamentale per Picture in picture. Ancora una volta, l'attuale esperienza offerta da un sito web di videoconferenza tramite l'API Picture in picture per <video> è limitata nello stile e nell'input. Con un documento completo in Picture in picture, il sito web può combinare facilmente più stream video in un'unica finestra Picture in picture senza dover fare affidamento su trucchi per la tela e fornire controlli personalizzati come inviare un messaggio, disattivare l'audio di un altro utente o alzare una mano.

Produttività

La ricerca ha dimostrato che gli utenti hanno bisogno di più modi per essere produttivi sul web. La funzionalità Documenti in Picture in picture offre alle app web la flessibilità necessaria per ottenere di più. Che si tratti di modifica di testo, creazione di note, elenchi di attività, messaggistica e chat o strumenti di progettazione e sviluppo, ora le app web possono mantenere i loro contenuti sempre accessibili.

Interfaccia

Proprietà

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

Metodi

documentPictureInPicture.requestWindow(options)

Restituisce una promessa che si risolve quando viene aperta una finestra Picture in picture. La promessa viene rifiutata se viene chiamato senza gesto dell'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 il valore è true, il pulsante "Torna alla scheda" viene nascosto nella finestra Picture in picture. Per impostazione predefinita, è false.

Eventi

documentPictureInPicture.onenter
Attivata il giorno documentPictureInPicture quando si apre una finestra Picture in picture.

Esempi

Il codice HTML seguente consente di impostare 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 codice JavaScript seguente 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 desiderate della finestra Picture in picture. Chrome potrebbe limitare i valori delle opzioni se sono troppo grandi o troppo piccoli per adattarsi a una finestra di dimensioni agevoli.

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

Nascondi il pulsante "Torna alla scheda" della finestra Picture in picture

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

Copiare i fogli di stile nella finestra Picture in picture

Per copiare tutti i fogli di stile CSS dalla finestra di origine, esegui il loop di styleSheets collegati esplicitamente o incorporati al documento e aggiungili alla finestra Picture in picture. Tieni presente che questa è una copia da eseguire una sola volta.

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

Gestisci la chiusura della finestra Picture in picture

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 è utile per ripristinare gli elementi dalla finestra Picture in picture, come mostrato di seguito.

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 in modo programmatico utilizzando il metodo close().

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

Ascolta quando il sito web inserisce Picture in picture

Ascolta l'evento "enter" il giorno 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 della finestra Picture in picture

Accedi agli elementi della finestra Picture in picture dall'oggetto restituito da documentPictureInPicture.requestWindow() o con documentPictureInPicture.window, come mostrato di seguito.

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 Picture in picture

Crea pulsanti e controlli e rispondi agli eventi di input dell'utente come "click", come faresti normalmente 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 Picture in picture

Utilizza i metodi della finestra 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);

Imposta lo stato attivo sulla finestra di apertura

Utilizza il metodo Finestra focus() per impostare lo stato attivo sulla finestra di apertura della 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 Picture in picture del CSS

Utilizza la modalità di visualizzazione picture-in-picture CSS per scrivere regole CSS specifiche da applicare solo quando (parte della) l'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

Player VideoJS

Puoi utilizzare la demo del player VideoJS dell'API Document Picture-in-Picture. Assicurati di controllare il codice sorgente.

Pomodoro

Anche Tomodoro, un'app web di pomodoro, sfrutta l'API Document Picture-in-Picture, se disponibile (vedi richiesta di pull GitHub).

Screenshot di Tomodoro, un&#39;app web di pomodoro.
Una finestra Picture in picture a Tomodoro.

Feedback

Ti invitiamo a inviare i problemi su GitHub con suggerimenti e domande.

Ringraziamenti

Immagine hero di Jakob Owens.