「動画」だけでなく、すべての要素でピクチャー イン ピクチャーで使用可能

François Beaufort
François Beaufort

Browser Support

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

Source

ドキュメント ピクチャー イン ピクチャー API を使用すると、任意の HTML コンテンツを入力できる最前面のウィンドウを開くことができます。これは、HTML <video> 要素のみをピクチャー イン ピクチャー(PIP)ウィンドウに配置できる既存の <video> 用の ピクチャー イン ピクチャー API を拡張したものです。

Document Picture-in-Picture API のピクチャー イン ピクチャー ウィンドウは、window.open() を使用して開いた空白の同一オリジン ウィンドウに似ていますが、いくつかの違いがあります。

  • ピクチャー イン ピクチャー ウィンドウは、他のウィンドウの上にフローティング表示されます。
  • ピクチャー イン ピクチャー ウィンドウは、開いたウィンドウよりも長く表示されることはありません。
  • ピクチャー イン ピクチャー ウィンドウを操作できない。
  • ピクチャー イン ピクチャー ウィンドウの位置はウェブサイトで設定できません。
Sintel の予告編動画を再生しているピクチャー イン ピクチャー ウィンドウ。
Document Picture-in-Picture API(デモ)で作成されたピクチャー イン ピクチャー ウィンドウ。

ステータス

ステップ ステータス
1. 説明を作成する 完了
2. 仕様の最初のドラフトを作成する 作成中
3. フィードバックを収集して設計をイテレーションする 作成中
4. オリジン トライアル 完了
5. リリース 完了(パソコン)

ユースケース

この API は、カスタム動画プレーヤー、ビデオ会議、生産性向上アプリなど、さまざまな方法で使用できます。

カスタム動画プレーヤー

ウェブサイトは、既存の <video> 用の Picture-in-Picture API を使用してピクチャー イン ピクチャーの動画エクスペリエンスを提供できますが、その機能は非常に限られています。既存の PiP ウィンドウでは、入力が少なく、スタイリングの機能も限られています。ピクチャー イン ピクチャーでドキュメント全体を表示することで、ウェブサイトはカスタム コントロールと入力(字幕、プレイリスト、タイムスクラバー、動画の評価など)を提供し、ユーザーの PiP 動画エクスペリエンスを向上させることができます。

ビデオ会議

ユーザーは、ビデオ会議セッション中にブラウザのタブを一時的に離れることがよくあります。たとえば、別のタブから通話にプレゼンテーションを行うとき、メモを取るとき、その他のマルチタスクを行うときなどです。ただし、ほとんどの場合、ユーザーは通話を表示したいと考えているため、これはピクチャー イン ピクチャーの理想的なユースケースです。繰り返しになりますが、ビデオ会議ウェブサイトが <video> 向けピクチャー イン ピクチャー API で提供できる現在のエクスペリエンスは、スタイルと入力が制限されています。ピクチャー イン ピクチャーの完全なドキュメントを使用すると、ウェブサイトは canvas ハックに頼ることなく、複数の動画ストリームを 1 つの PIP ウィンドウに簡単に統合し、メッセージの送信、他のユーザーのミュート、挙手などのカスタム コントロールを提供できます。

仕事効率化

調査によると、ユーザーはウェブ上で生産性を高めるための方法を求めています。ピクチャー イン ピクチャーのドキュメントにより、ウェブアプリの柔軟性が高まり、より多くのことを実行できるようになります。テキスト編集、メモ、タスクリスト、メッセージングとチャット、デザインと開発ツールなど、ウェブアプリのコンテンツを常にアクセス可能な状態に保つことができます。

インターフェース

プロパティ

documentPictureInPicture.window
現在のピクチャー イン ピクチャー ウィンドウがあれば返します。それ以外の場合は、null を返します。

メソッド

documentPictureInPicture.requestWindow(options)

ピクチャー イン ピクチャー ウィンドウが開いたときに解決される Promise を返します。ユーザー操作なしで呼び出された場合、Promise は拒否されます。options 辞書には、次のオプションのメンバーが含まれています。

width
ピクチャー イン ピクチャー ウィンドウの初期幅を設定します。
height
ピクチャー イン ピクチャー ウィンドウの初期の高さを設定します。
disallowReturnToOpener
が true の場合、ピクチャー イン ピクチャー ウィンドウの [タブに戻る] ボタンを非表示にします。デフォルトでは false です。
preferInitialWindowPlacement
true の場合、ピクチャー イン ピクチャー ウィンドウをデフォルトの位置とサイズで開きます。デフォルトでは false です。

イベント

documentPictureInPicture.onenter
ピクチャー イン ピクチャー ウィンドウが開いたときに documentPictureInPicture で発生します。

次の HTML は、カスタム動画プレーヤーと、ピクチャー イン ピクチャー ウィンドウで動画プレーヤーを開くボタン要素を設定します。

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

ピクチャー イン ピクチャー ウィンドウを開く

次の JavaScript は、ユーザーがボタンをクリックしたときに documentPictureInPicture.requestWindow() を呼び出して、空白のピクチャー イン ピクチャー ウィンドウを開きます。返された Promise は、ピクチャー イン ピクチャー ウィンドウの JavaScript オブジェクトで解決されます。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);
});

ピクチャー イン ピクチャー ウィンドウのサイズを設定する

ピクチャー イン ピクチャー ウィンドウのサイズを設定するには、documentPictureInPicture.requestWindow()width オプションと height オプションを理想的な PIP ウィンドウ サイズに設定します。オプションの値が大きすぎたり小さすぎたりして、ユーザー フレンドリーなウィンドウ サイズに収まらない場合、Chrome はオプションの値を小さくすることがあります。

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

PIP ウィンドウの [タブに戻る] ボタンを非表示にする

ユーザーがオープナー タブに戻るためのボタンをピクチャー イン ピクチャー ウィンドウに表示しないようにするには、documentPictureInPicture.requestWindow()disallowReturnToOpener オプションを 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,
  });
});

PiP をデフォルトの位置とサイズで開く

以前のピクチャー イン ピクチャー ウィンドウの位置やサイズを再利用しないようにするには、documentPictureInPicture.requestWindow()preferInitialWindowPlacement オプションを true に設定します。

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

スタイルシートを PiP にコピー

元のウィンドウからすべての CSS スタイルシートをコピーするには、ドキュメントに明示的にリンクされているか埋め込まれている styleSheets をループ処理し、ピクチャー イン ピクチャー ウィンドウに追加します。これは 1 回限りのコピーです。

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

PIP ウィンドウが閉じられたときの処理

ウィンドウの "pagehide" イベントをリッスンして、ピクチャー イン ピクチャー ウィンドウが閉じられたタイミング(ウェブサイトによって開始されたか、ユーザーが手動で閉じたか)を把握します。イベント ハンドラは、次に示すように、ピクチャー イン ピクチャー ウィンドウから要素を取り出すのに適した場所です。

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

close() メソッドを使用して、ピクチャー イン ピクチャー ウィンドウをプログラムで閉じます。

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

ウェブサイトが PiP に入ったときにリッスンする

documentPictureInPicture"enter" イベントをリッスンして、ピクチャー イン ピクチャー ウィンドウが開いたタイミングを把握します。このイベントには、ピクチャー イン ピクチャー ウィンドウにアクセスするための window オブジェクトが含まれています。

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

PiP ウィンドウの要素にアクセスする

ピクチャー イン ピクチャー ウィンドウの要素には、documentPictureInPicture.requestWindow() によって返されたオブジェクトから、または 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;
}

PIP ウィンドウからのイベントを処理する

ボタンやコントロールを作成し、JavaScript でユーザーの入力イベント("click" など)に応答します。

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

PIP ウィンドウのサイズを変更する

ピクチャー イン ピクチャー ウィンドウのサイズを変更するには、resizeBy() ウィンドウ メソッドと resizeTo() ウィンドウ メソッドを使用します。どちらのメソッドでもユーザー操作が必要です。

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() Window メソッドを使用して、ピクチャー イン ピクチャー ウィンドウからオープナー ウィンドウにフォーカスします。このメソッドにはユーザー操作が必要です。

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

CSS PiP 表示モード

CSS の picture-in-picture 表示モードを使用して、ウェブアプリの一部がピクチャー イン ピクチャー モードで表示される場合にのみ適用される特定の CSS ルールを記述します。

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

特徴検出

ドキュメント ピクチャー イン ピクチャー API がサポートされているかどうかを確認するには、次のコードを使用します。

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

デモ

Tomodoro は、ポモドーロ ウェブアプリです。
Tomodoro のピクチャー イン ピクチャー ウィンドウ。

フィードバックをお寄せください

提案や質問については、GitHub で Issue を作成してください。