🌐

Chrome130から使えるDocument Picture-in-Picture APIを試してみた

2024/11/17に公開

はじめに

Chrome 130が2024年10月9日にリリースされ、Document Picture-in-Picture APIが正式に利用可能になりました。

ピクチャーインピクチャー機能自体はこれまでも存在し、動画をミニプレイヤーとして別ウィンドウで表示することができました。しかし、これまでのピクチャーインピクチャーでは動画コンテンツしか表示できないという制限がありました。今回のアップデートにより、任意のDOM要素をミニプレイヤーとして表示できるようになり、より柔軟な活用が可能になりました。

この機能は以前からGoogle Meetで活用されています。会議中に別の作業をしながらミーティングの参加者を表示できる機能がその一例です。

Google Meetのピクチャーインピクチャー機能

Google MeetはGoogle謹製なので、特別にChrome 130以前からこの機能を利用することができていたようです。

また、Spotifyもこの新しいDocument Picture-in-Picture APIを採用し、ミニプレイヤー機能を提供しています。

試してみた

ということで早速試してみました。
作ったのは簡単なストップウォッチです。
sample

実際のページは↓から確認できます。
https://rsasage.com/doc-pic-in-pic/?v=9

ウィンドウ上のボタンも機能して、他のアプリケーションより上に表示されていることが確認できると思います。

実装

Picture in Pictureウィンドウの表示

Document Picture-in-Picture APIではdocumentPictureInPictureというオブジェクトを使います。
requestWindowメソッドを呼ぶと先ほどのPicture in Pictureウィンドウが表示されます。

const pipWindow = await window.documentPictureInPicture.requestWindow({
  width: 600,
  height: 400
});

widthheightも指定できますが、省略しても構いません。

Document Picture-in-Picture APIに対応しているかの確認

Document Picture-in-Picture APIに対応しているかどうかはwindowにdocumentPictureInPictureがあるかを確認すれば判定できます。

if (!("documentPictureInPicture" in window)) {
  alert("ピクチャーインピクチャーはサポートされていません");
  return;
}

Picture in PictureウィンドウにDOM Elementを追加

requestWindowで取得したwindowに↓のようにDOM Elementを追加することで表示コンテンツを制御できます。

const pipContent = document.querySelector("#pip");
pipWindow.document.body.append(pipContent);

Picture in Picture終了時の挙動を設定

requestWindowで取得したwindowのunloadイベントをlistenすることでPicture in Picture終了時の挙動を設定できます。

pipWindow.addEventListener("unload", (event) => {
  // Picture in Picture終了時の挙動
});

全体像

下記がより詳しい実装になります。

index.html
<body>
  <div id="container">
    <div id="pip">
      <!-- 1. この位置にstyleを書かないとピクチャーインピクチャー時に適用されない -->
      <style>
        #pip {
          text-align: center;
          padding: 2rem;
          position: relative;
          background-color: #f0f0f0;
        }
        /* 中略 */
      </style>
      <button id="pipBtn">
        <!-- ピクチャーインピクチャーのアイコン -->
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 18 L4 18 L4 6 L20 6 L20 8"></path><rect x="12" y="12" width="10" height="8"></rect></svg>
      </button>
      <h1>ストップウォッチ</h1>
      <div id="display">00:00</div>
      <button id="startBtn">スタート</button>
    </div>
  </div>

  <script>
    /* 中略 */
    pipBtn.addEventListener('click', async function () {
      // 2. Document Picture-in-Picture API がサポートされているか確認
      if (!("documentPictureInPicture" in window)) {
        alert("ピクチャーインピクチャーはサポートされていません");
        return;
      }
      // 3. ピクチャーインピクチャーに表示する要素を取得
      const pipContent = document.querySelector("#pip");
      // 4. ピクチャーインピクチャーのウィンドウを作成
      const pipWindow = await window.documentPictureInPicture.requestWindow({
        width: pipContent.clientWidth,
        height: pipContent.clientHeight
      });
      // 5. ピクチャーインピクチャーの背景色を設定
      pipBackground = window.getComputedStyle(pipContent).backgroundColor;
      pipWindow.document.body.style.backgroundColor = pipBackground;
      pipWindow.document.body.style.margin = "0";
      // 6. ピクチャーインピクチャーのウィンドウにコンテンツを追加
      pipWindow.document.body.append(pipContent);
      // 7. ピクチャーインピクチャーのウィンドウが閉じられたときにコンテンツを元の位置に戻す
      pipWindow.addEventListener("unload", (event) => {
        const container = document.querySelector("#container");
        const pipContent = event.target.querySelector("#pip");
        container.append(pipContent);
      });
    });
  </script>
</body>

headタグ内や別ファイルに書いたスタイルシートがPicture in Pictureウィンドウには適用されないので、いろいろ工夫していています。

  • Picture in Pictureウィンドウに表示するDOM Elementの中にstyleを書くことでスタイルが適用されるようにしています。インラインのCSSでもOKです。
  • Picture in Pictureウィンドウの背景色を対象DOM Elementと同じ色に設定しています。設定しないと白色が表示されます。
  • マージンを0に設定して、幅高さを元の要素と同じにすることで、元の要素と大きさが同じPicture in Pictureウィンドウを表示しています。

全体のソースコードはGitHubに置いています。

https://github.com/Arahabica/Document-Picture-in-Picture-sample

サブウィンドウとの比較

似たような機能としてサブウィンドウがありますが、違いはなんでしょう。
主な違いは下記3点になるかと思います。

  1. Picture in Pictureウィンドウは常時、他のアプリより上に表示される
  2. サブウィンドウはアドレスバーが表示される分ダサく見える
  3. Picture in Pictureウィンドウは全体で1つしか表示できないが、サブウィンドウはいくつでも表示できる

2.のダサい問題ですが、実際にサブウィンドウと比較するとこのようになります。
サブウィンドウ

Picture in Picture

さらにPicture in Pictureの背景色をトップバーと同じ黒色(#232323)にするとバーが目立たなくなり、より洗練された印象になります。
Picture in Picture dark

先に紹介したSpotifyも背景色を黒色にしているようです。

サブウィンドウ、黒背景色との実際の比較は下記ページにて確認できます。
https://rsasage.com/doc-pic-in-pic/vs?v=9

おわりに

現在、Document Picture-in-Picture APIの主な活用例は、Google Meetに代表されるビデオ会議システムや、Spotifyのような動画・音楽プレイヤーとなっています。常に他のアプリケーションの上に表示される強力な特性は、使用シーンを慎重に検討する必要があります。

しかし、この制約は逆に「ユーザーが常に目にしておきたい情報」や「作業中でもすぐにアクセスしたい機能」を提供する際のチャンスともなります。タイマーやタスク管理、システムモニタリングなど、まだ見ぬ活用方法が眠っているかもしれません。ぜひ皆さんも、この新しいAPIを使った新しいユーザー体験を考えてみてください。

参考資料

https://developer.mozilla.org/en-US/docs/Web/API/Document_Picture-in-Picture_API
https://developer.chrome.com/docs/web-platform/document-picture-in-picture/
https://github.com/WICG/document-picture-in-picture

ボイスアップラボ

Discussion