文件子母畫面 API 可開啟永遠置頂的視窗,並填入任意 HTML 內容。這項 API 擴充了現有的 Picture-in-Picture API for <video>
,後者只允許將 HTML <video>
元素放入子母畫面視窗。
Document Picture-in-Picture API 中的子母畫面視窗與透過 window.open()
開啟的空白同源視窗類似,但有以下差異:
- 子母畫面視窗會浮動在其他視窗上方。
- 子母畫面視窗的生命週期絕不會超過開啟視窗。
- 無法在子母畫面視窗中瀏覽。
- 網站無法設定子母畫面視窗位置。

目前狀態
步驟 | 狀態 |
---|---|
1. 建立說明 | 完成 |
2. 草擬規格初稿 | 處理中 |
3. 收集意見回饋並反覆修正設計 | 處理中 |
4. 來源試用 | 完成 |
5. 啟動 | 完成 (電腦版) |
用途
自訂影片播放器
網站可透過現有的 <video>
子母畫面 API 提供子母畫面影片體驗,但功能非常有限。現有的子母畫面視窗可接受的輸入內容很少,且樣式設定能力有限。透過子母畫面中的完整文件,網站可以提供自訂控制項和輸入內容 (例如字幕、播放清單、時間軸、喜歡和不喜歡影片),提升使用者的子母畫面影片體驗。
視訊會議
使用者在視訊會議期間離開瀏覽器分頁的原因有很多 (例如在通話中顯示其他分頁或執行多工),但他們仍希望看到通話畫面,因此子母畫面是主要的使用情境。再次提醒,目前視訊會議網站透過 <video>
子母畫面 API 提供的體驗,在樣式和輸入方面都受到限制。有了子母畫面中的完整文件,網站就能輕鬆將多個影片串流合併到單一子母畫面視窗,不必依賴畫布破解,並提供自訂控制項,例如傳送訊息、將其他使用者設為靜音或舉手。
效率提升
研究顯示,使用者需要更多網頁生產力工具。網頁應用程式可透過子母畫面中的文件,彈性完成更多工作。無論是文字編輯、記事、工作清單、訊息和即時通訊,還是設計和開發工具,網頁應用程式現在都能確保內容隨時可存取。
介面
屬性
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
選項設為所需的子母畫面視窗大小。如果選項值太大或太小,無法配合使用者友善的視窗大小,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,
});
});
以預設位置和大小開啟子母畫面視窗
如要避免重複使用先前子母畫面視窗的位置或大小,請將 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,
});
});
將樣式表複製到子母畫面視窗
如要從原始視窗複製所有 CSS 樣式表,請透過明確連結或內嵌至文件中的 styleSheets
進行迴圈,然後將這些樣式表附加至子母畫面視窗。請注意,這項作業只會執行一次。
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;
}
處理子母畫面視窗的事件
建立按鈕和控制項,並回應使用者的輸入事件 (例如 "click"
),就像在 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);
調整子母畫面視窗大小
使用 resizeBy()
和 resizeTo()
Window 方法調整子母畫面視窗大小。這兩種方法都需要使用者手勢。
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 子母畫面顯示模式
使用 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 播放器
您可以透過 VideoJS 播放器示範,試用 Document Picture-in-Picture API。
Pomodoro
Tomodoro 是一款番茄工作法網頁應用程式,也會在適用時使用 Document Picture-in-Picture API。請參閱他們的 GitHub 提取要求。

提供意見
歡迎前往 GitHub 提報問題,並提供建議和提出疑問。