视频会议开到一半要切出去看文档?浏览器这个 API 把整个页面变成了画中画——Document PiP 把这件事彻底变了
你有没有遇到过这种场景:视频会议开着,但切到别的标签页就看不见对方了;在线课要边看教程边做笔记,但播放窗口老是被别的页面挡住。以前这种需求要么靠浏览器原生画中画(只能放一个video标签),要么靠 window.open 自己写悬浮窗(导航和层级问题一堆)。
Chrome 116 给了一个新选项:Document Picture-in-Picture API。它本质上是一个「带脑子」的 window.open()——内容自己定、永远浮在顶层、不会自己跳转、关了还不会留孤儿窗口。
和传统 PiP 的本质区别
传统 <video> 的 Picture-in-Picture 只能塞一个视频进去,控件都是浏览器生成的,没法自定义。Document PiP 直接给你一个空白窗口,你可以往里面塞任意 HTML——视频、按钮、进度条、整个聊天面板,随你怎么玩。
const btn = document.querySelector("#openPip");
btn.addEventListener("click", async () => {
// 检测浏览器支持
if (!("documentPictureInPicture" in window)) {
alert("浏览器不支持 Document PiP");
return;
}
const pipWindow = await window.documentPictureInPicture.requestWindow({
width: 640,
height: 480,
});
// 把页面里的播放器移进 PiP 窗口
const player = document.querySelector("#player");
pipWindow.document.body.append(player);
});
这段代码打开一个 640×480 的空白悬浮窗,然后把页面里的 #player 元素移进去。用户可以把窗口拖到副屏,继续干别的事,主窗口里的内容还在原位。
跨窗口通信:两个文档是隔离的
这是最容易踩的坑:PiP 窗口和主页面是两个完全隔离的 JavaScript 上下文,不能共享变量,不能直接调用对方函数,数据同步只能走 postMessage。
// 主页面发消息到 PiP 窗口
const pipWindow = documentPictureInPicture.window;
pipWindow.postMessage({ type: "PLAY" }, "*");
// PiP 窗口监听
window.addEventListener("message", (event) => {
if (event.source !== documentPictureInPicture.window) return;
if (event.data.type === "PLAY") video.play();
});
反过来同理,PiP 窗口里的脚本也可以 postMessage 回去通知主页面。关键是要校验 event.source,否则有 XSS 风险。
getstream.io 在视频会议场景里的最佳实践还提到一点:把样式表从主窗口复制到 PiP 窗口里,否则里面是裸 HTML。requestWindow() 返回的窗口没有任何样式。
window.document.head
.querySelectorAll("link[rel="stylesheet"], style")
.forEach((node) => {
pipWindow.document.head.appendChild(node.cloneNode(true));
});
还有一个很多人不知道的状态坑
PiP 窗口关闭后,documentPictureInPicture.window 不会自动置空,还保留着对那个已关闭窗口的引用。如果不检查就再次调用 requestWindow(),会抛出 InvalidStateError。
// 监听窗口关闭事件
documentPictureInPicture.addEventListener("leave", () => {
// 窗口被关了,清理状态
pipWindow = null;
});
// 打开前先检查
async function openPip() {
if (documentPictureInPicture.window) {
// 窗口已存在,先关掉
documentPictureInPicture.window.close();
}
pipWindow = await documentPictureInPicture.requestWindow();
}
浏览器支持现状
目前只有 Chromium 内核完整支持:Chrome 116+、Edge 116+、Opera 102+。Firefox 151 也支持了。Safari 全系列没有,iOS 更不用说了。
这个现状决定了它必须走渐进增强的路子:先保证主功能在所有浏览器里可用,再给支持的浏览器加上 Document PiP 作为增强选项。
什么场景值得用
目前最成熟的三个场景:
- 自定义视频播放器:告别浏览器原生的那几个按钮,做自己的播放/暂停/进度/音量控制
- 视频会议悬浮窗口:把参会者画面或控制面板单独拎出来,切到别的标签页也能看见
- 在线教育边看边做:代码编辑器+浏览器预览的组合站,把预览区弹出到副屏,主屏留给编辑器
简单来说,只要你想把「某个 UI 区域」从主窗口里解放出来同时保持交互,Document PiP 就比 window.open 靠谱得多。
下一步
Chrome 116 是 2023 年 8 月的版本,如果你的用户主要是 Chromium 内核用户,现在已经可以上了。检测方法只要一行:
const supported = "documentPictureInPicture" in window;
不支持的浏览器走原来的方案降级,别让这个 API 成为可用性的阻碍。
评论区
登录后可评论。