Picture-in-picture pour tous les éléments, pas uniquement les <vidéos>

François Beaufort
François Beaufort

Browser Support

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

Source

L'API Document Picture-in-Picture permet d'ouvrir une fenêtre toujours au premier plan qui peut être remplie avec du contenu HTML arbitraire. Elle étend l'API Picture-in-Picture existante pour <video>, qui n'autorise qu'un élément HTML <video> à être placé dans une fenêtre Picture-in-Picture (PiP).

La fenêtre Picture-in-Picture de l'API Document Picture-in-Picture est semblable à une fenêtre vide de même origine ouverte à l'aide de window.open(), à quelques différences près :

  • La fenêtre Picture-in-Picture flotte au-dessus des autres fenêtres.
  • La fenêtre Picture-in-Picture ne survit jamais à la fenêtre d'ouverture.
  • La fenêtre Picture-in-Picture ne peut pas être parcourue.
  • La position de la fenêtre Picture-in-Picture ne peut pas être définie par le site Web.
Fenêtre Picture-in-picture diffusant la bande-annonce de Sintel.
Fenêtre Picture-in-Picture créée avec l'API Document Picture-in-Picture (démonstration).

État

Étape État
1. Créer une explication Fin
2. Créer une première ébauche de la spécification In progress
3. Recueillir des commentaires et itérer la conception In progress
4. Essai Origin Trial Fin
5. Lancer Fin (ordinateur)

Cas d'utilisation

Vous pouvez utiliser cette API de différentes manières, y compris pour les lecteurs vidéo personnalisés, les visioconférences et les applications de productivité.

Lecteur vidéo personnalisé

Un site Web peut offrir une expérience vidéo Picture-in-Picture avec l'API Picture-in-Picture existante pour <video>, mais elle est très limitée. La fenêtre PiP existante accepte peu d'entrées et offre des possibilités limitées pour les styliser. Avec un document complet en Picture-in-Picture, le site Web peut fournir des commandes et des entrées personnalisées (par exemple, des sous-titres, des playlists, un curseur temporel, des boutons "J'aime" et "Je n'aime pas") pour améliorer l'expérience vidéo PiP de l'utilisateur.

Visioconférence

Les utilisateurs quittent souvent temporairement l'onglet du navigateur lors d'une visioconférence, par exemple lorsqu'ils présentent un autre onglet à l'appel, prennent des notes ou effectuent d'autres activités multitâches. Toutefois, dans la plupart des cas, l'utilisateur souhaite toujours voir l'appel. Il s'agit donc d'un cas d'utilisation idéal pour le Picture-in-Picture. Là encore, l'expérience actuelle qu'un site Web de visioconférence peut offrir avec l'API Picture-in-Picture pour <video> est limitée en termes de style et d'entrée. Avec un document complet en Picture-in-Picture, le site Web peut facilement combiner plusieurs flux vidéo dans une seule fenêtre PiP, sans avoir recours à des hacks de canevas, et fournir des commandes personnalisées, telles que l'envoi d'un message, la désactivation du son d'un autre utilisateur ou la levée de la main.

Productivité

Des études ont montré que les utilisateurs ont besoin de plus de moyens pour être productifs sur le Web. Le document en Picture-in-Picture offre aux applications Web la flexibilité nécessaire pour en faire plus. Qu'il s'agisse d'outils d'édition de texte, de prise de notes, de listes de tâches, de messagerie et de chat, ou d'outils de conception et de développement, les applications Web peuvent désormais rendre leur contenu toujours accessible.

Interface

Propriétés

documentPictureInPicture.window
Renvoie la fenêtre Picture-in-Picture actuelle, le cas échéant. Sinon, renvoie null.

Méthodes

documentPictureInPicture.requestWindow(options)

Renvoie une promesse qui se résout lorsqu'une fenêtre Picture-in-Picture est ouverte. La promesse est rejetée si elle est appelée sans geste de l'utilisateur. Le dictionnaire options contient les membres facultatifs suivants :

width
Définit la largeur initiale de la fenêtre Picture-in-Picture.
height
Définit la hauteur initiale de la fenêtre Picture-in-Picture.
disallowReturnToOpener
Masque le bouton "Retour à l'onglet" dans la fenêtre Picture-in-Picture si la valeur est "true". La valeur par défaut est "false".
preferInitialWindowPlacement
Ouvre la fenêtre Picture-in-Picture dans sa position et sa taille par défaut si la valeur est "true". La valeur par défaut est "false".

Événements

documentPictureInPicture.onenter
Déclenché sur documentPictureInPicture lorsqu'une fenêtre Picture-in-Picture est ouverte.

Exemples

Le code HTML suivant configure un lecteur vidéo personnalisé et un élément de bouton pour ouvrir le lecteur vidéo dans une fenêtre Picture-in-Picture.

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

Ouvrir une fenêtre Picture-in-picture

Le code JavaScript suivant appelle documentPictureInPicture.requestWindow() lorsque l'utilisateur clique sur le bouton pour ouvrir une fenêtre Picture-in-Picture vide. La promesse renvoyée est résolue avec un objet JavaScript de fenêtre Picture-in-Picture. Le lecteur vidéo est déplacé vers cette fenêtre à l'aide de 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);
});

Définir la taille de la fenêtre Picture-in-Picture

Pour définir la taille de la fenêtre Picture-in-Picture, définissez les options width et height de documentPictureInPicture.requestWindow() sur la taille idéale de la fenêtre PiP. Chrome peut réduire les valeurs des options si elles sont trop grandes ou trop petites pour s'adapter à une taille de fenêtre conviviale.

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

Masquer le bouton "Retour à l'onglet" dans la fenêtre PiP

Pour masquer le bouton de la fenêtre Picture-in-Picture qui permet à l'utilisateur de revenir à l'onglet d'ouverture, définissez l'option disallowReturnToOpener de documentPictureInPicture.requestWindow() sur 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,
  });
});

Ouvrir la fenêtre PiP à la position et à la taille par défaut

Pour ne pas réutiliser la position ni la taille de la fenêtre Picture-in-Picture précédente, définissez l'option preferInitialWindowPlacement de documentPictureInPicture.requestWindow() sur true.

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

Copier des feuilles de style dans la fenêtre PiP

Pour copier toutes les feuilles de style CSS de la fenêtre d'origine, parcourez les styleSheets explicitement liées ou intégrées au document, puis ajoutez-les à la fenêtre Picture-in-Picture. Notez qu'il s'agit d'une copie unique.

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

Gérer la fermeture de la fenêtre PiP

Écoutez l'événement "pagehide" de la fenêtre pour savoir quand la fenêtre Picture-in-Picture est fermée (soit parce que le site Web l'a initiée, soit parce que l'utilisateur l'a fermée manuellement). Le gestionnaire d'événements est un bon endroit pour récupérer les éléments de la fenêtre Picture-in-Picture, comme illustré ici.

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

Fermez la fenêtre Picture-in-Picture par programmation à l'aide de la close() méthode.

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

Écouter le moment où le site Web passe en mode PiP

Écoutez l'événement "enter" sur documentPictureInPicture pour savoir quand une fenêtre Picture-in-Picture est ouverte. L'événement contient un objet window pour accéder à la fenêtre Picture-in-Picture.

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

Accéder aux éléments de la fenêtre PiP

Accédez aux éléments de la fenêtre Picture-in-Picture à partir de l'objet renvoyé par documentPictureInPicture.requestWindow() ou avec 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;
}

Gérer les événements de la fenêtre PiP

Créez des boutons et des commandes, et répondez aux événements d'entrée de l'utilisateur (tels que "click"), comme toujours en 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);

Redimensionner la fenêtre PiP

Utilisez les méthodes resizeBy() et resizeTo() de la fenêtre pour redimensionner la fenêtre Picture-in-Picture. Les deux méthodes nécessitent un geste de l'utilisateur.

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

Sélectionner la fenêtre d'ouverture

Utilisez la méthode focus() Window pour sélectionner la fenêtre d'ouverture à partir de la fenêtre Picture-in-Picture. Cette méthode nécessite un geste de l'utilisateur.

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

Mode d'affichage PiP CSS

Utilisez le mode d'affichage CSS picture-in-picture pour écrire des règles CSS spécifiques qui ne sont appliquées que lorsque (une partie de) l'application Web est affichée en mode Picture-in-Picture.

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

Détection de fonctionnalités

Pour vérifier si l'API Document Picture-in-Picture est compatible, utilisez :

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

Démonstrations

  • Lecteur VideoJS : essayez la démonstration du lecteur VideoJS de l'API Document Picture-in-Picture.
  • Tomodoro, une application Web Pomodoro, tire parti de l'API Document Picture-in-Picture lorsqu'elle est disponible. Consultez sa demande d'extraction GitHub.
Tomodoro, une application Web Pomodoro.
Fenêtre Picture-in-Picture dans Tomodoro.

Envoyer des commentaires

Créez des demandes sur GitHub avec des suggestions et des questions.