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

François Beaufort
François Beaufort

対応ブラウザ

  • 116
  • 116
  • x
  • x

ソース

Document Picture-in-Picture API を使用すると、任意の HTML コンテンツを入力できる常時表示ウィンドウを開くことができます。これは、既存の <video> 用の Picture-in-Picture API を拡張し、HTML の <video> 要素のみをピクチャー イン ピクチャー ウィンドウに配置できるようにします。

Document Picture-in-Picture API の Picture-in-Picture ウィンドウは、window.open() を介して開かれる空白の同一オリジン ウィンドウに似ていますが、次のような違いがあります。

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

現在のステータス

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

使用例

カスタム動画プレーヤー

ウェブサイトは、既存の <video> 用の Picture-in-Picture API を使用してピクチャー イン ピクチャーの動画エクスペリエンスを提供できますが、機能は非常に限定的です。既存のピクチャー イン ピクチャー ウィンドウは入力を受け付けることができ、スタイル設定機能も限られています。ピクチャー イン ピクチャーの完全なドキュメントにより、ウェブサイトはカスタム コントロールと入力(字幕、再生リスト、タイムスクラバー、動画の高評価と低評価など)を提供して、ユーザーのピクチャー イン ピクチャー動画のエクスペリエンスを改善できます。

ビデオ会議

ビデオ会議のセッション中は、さまざまな理由(通話に別のタブを画面共有する、マルチタスクを行うなど)で通話の視聴を続けながらブラウザタブを離れることがよくあります。これはピクチャー イン ピクチャーの主要なユースケースです。繰り返しになりますが、現在のところ、ビデオ会議ウェブサイトが <video> の Picture-in-Picture API を介して提供できるスタイルと入力機能は制限されています。ピクチャー イン ピクチャーの完全なドキュメントにより、ウェブサイトはキャンバス ハックに頼ることなく、複数の動画ストリームを 1 つの PIP ウィンドウに簡単に結合でき、メッセージの送信、別のユーザーのミュート、挙手などのカスタム コントロールを提供できます。

生産性

調査によると、ユーザーはウェブ上で生産性を高める方法をさらに必要としていることがわかっています。ピクチャー イン ピクチャーのドキュメントにより、ウェブアプリでさまざまなタスクを柔軟に行えます。テキスト編集、メモ作成、タスクリスト、メッセージとチャット、デザイン / 開発ツールなど、ウェブアプリのコンテンツにいつでもアクセスできるようになりました。

インターフェース

プロパティ

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

Methods

documentPictureInPicture.requestWindow(options)

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

width
ピクチャー イン ピクチャー ウィンドウの初期の幅を設定します。
height
ピクチャー イン ピクチャー ウィンドウの初期の高さを設定します。
disallowReturnToOpener
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 オプションを、目的のピクチャー イン ピクチャー ウィンドウ サイズに設定します。オプションの値が大きすぎるか、小さすぎてユーザー フレンドリーなウィンドウ サイズに収まらない場合、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);
});

ピクチャー イン ピクチャー ウィンドウの [タブに戻る] ボタンを非表示にする

ピクチャー イン ピクチャー ウィンドウ内で、ユーザーがオープナー タブに戻るボタンを非表示にするには、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,
  });
});

スタイルシートをピクチャー イン ピクチャー ウィンドウにコピーする

元のウィンドウからすべての 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);
});

ピクチャー イン ピクチャー ウィンドウが閉じたときを処理する

ウィンドウの "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();

ウェブサイトがピクチャー イン ピクチャーに切り替わったときに再生します

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

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

ピクチャー イン ピクチャー ウィンドウの要素にアクセスする

以下に示すように、ピクチャー イン ピクチャー ウィンドウ内の要素には、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;
}

ピクチャー イン ピクチャー ウィンドウからのイベントの処理

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

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

ピクチャー イン ピクチャー ウィンドウのサイズを変更するには、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() ウィンドウ メソッドを使用します。このメソッドにはユーザー操作が必要です。

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

CSS ピクチャー イン ピクチャーの表示モード

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

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

機能検出

Document Picture-in-Picture API がサポートされているかどうかを確認するには、次のコマンドを使用します。

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

デモ

VideoJS プレーヤー

Document Picture-in-Picture API の VideoJS プレーヤーのデモを使用して動画を再生できます。必ずソースコードを確認してください。

ポモドーロ

Pomodoro ウェブアプリの Tomodoro も、Document Picture-in-Picture API(利用可能な場合)を利用しています(GitHub の pull リクエストを参照)。

ポモドーロ ウェブアプリの Tomodoro のスクリーンショット。
Tomodoro のピクチャー イン ピクチャー ウィンドウ。

フィードバック

提案や質問がある場合は、GitHub で問題を報告してください。

謝辞

ヒーロー画像 by Jakob Owens