ChromeのDocument Picture-in-Picture APIを試してみた
はじめに
ChromeにDocument Picture-in-Picture APIという機能が去年追加されました。
ピクチャーインピクチャー機能自体はこれまでも存在し、動画をミニプレイヤーとして別ウィンドウで表示することができました。しかし、これまでのピクチャーインピクチャーでは動画コンテンツしか表示できないという制限がありました。Document Picture-in-Picture APIにより、任意のDOM要素をミニプレイヤーとして表示できるようになり、より柔軟な活用が可能になりました。
この機能はGoogle Meetでも活用されています。会議中に別の作業をしながらミーティングの参加者を表示できる機能がその一例です。
また、Spotifyもこの新しいDocument Picture-in-Picture APIを採用し、ミニプレイヤー機能を提供しています。
試してみた
ということで早速試してみました。
作ったのは簡単なストップウォッチです。
実際のページは↓から確認できます。
ウィンドウ上のボタンも機能して、他のアプリケーションより上に表示されていることが確認できると思います。
実装
Picture in Pictureウィンドウの表示
Document Picture-in-Picture APIではdocumentPictureInPicture
というオブジェクトを使います。
requestWindow
メソッドを呼ぶと先ほどのPicture in Pictureウィンドウが表示されます。
const pipWindow = await window.documentPictureInPicture.requestWindow({
width: 600,
height: 400
});
width
とheight
も指定できますが、省略しても構いません。
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終了時の挙動
});
全体像
下記がより詳しい実装になります。
<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に置いています。
サブウィンドウとの比較
似たような機能としてサブウィンドウがありますが、違いはなんでしょう。
主な違いは下記3点になるかと思います。
- Picture in Pictureウィンドウは常時、他のアプリより上に表示される
- サブウィンドウはアドレスバーが表示される分ダサく見える
- Picture in Pictureウィンドウは全体で1つしか表示できないが、サブウィンドウはいくつでも表示できる
2.のダサい問題ですが、実際にサブウィンドウと比較するとこのようになります。
さらにPicture in Pictureの背景色をトップバーと同じ黒色(#232323)にするとバーが目立たなくなり、より洗練された印象になります。
先に紹介したSpotifyも背景色を黒色にしているようです。
サブウィンドウ、黒背景色との実際の比較は下記ページにて確認できます。
おわりに
現在、Document Picture-in-Picture APIの主な活用例は、Google Meetに代表されるビデオ会議システムや、Spotifyのような動画・音楽プレイヤーとなっています。常に他のアプリケーションの上に表示される強力な特性は、使用シーンを慎重に検討する必要があります。
しかし、この制約は逆に「ユーザーが常に目にしておきたい情報」や「作業中でもすぐにアクセスしたい機能」を提供する際のチャンスともなります。タイマーやタスク管理、システムモニタリングなど、まだ見ぬ活用方法が眠っているかもしれません。ぜひ皆さんも、この新しいAPIを使った新しいユーザー体験を考えてみてください。
参考資料
Discussion