你以为画中画只能浮一个视频?今天 Document PiP 把整张页面都漂起来了
你知道画中画(Picture-in-Picture)这个 API 已经出来很多年了吗?但它一直有个硬伤:只能浮一个 <video> 元素。你在小窗里看到的永远只有视频本身,弹幕没有、进度条没有、播放/暂停按钮没有,更别说让它浮一个聊天面板或者白板了。
所以很长一段时间里,「浏览器画中画」这个能力被用得很克制——大家要么忍了,要么干脆不推荐这个功能。
Chrome 116(2023年9月)开始,Document Picture-in-Picture API 正式稳定。这个 API 把画中画的格局彻底打开了:现在你可以把任意 HTML 内容塞进一个永远浮在最上层的窗口里,包括按钮、表单、聊天框、图表、甚至整个视频会议界面。
换句话说,画中画从「视频播放器专属」变成了「浏览器里的第二个窗口」。
传统 PiP vs Document PiP:根本区别在哪
传统 Picture-in-Picture API 只能接收一个 <video> 元素,然后把浏览器原生生成的那几个播放控件放进去。开发者没法定制,样式也不能改,用户看到的就是黑底加几个固定按钮。
Document PiP 完全不一样。你拿到的是一个完整的 Window 对象——可以往里面塞任何 HTML,可以复制样式表过去,可以在里面执行 JavaScript,可以监听用户关闭事件然后把内容移回来。整个体验完全在你的掌控之下。
用一个实际的场景来对比:
传统 PiP:用户在看你的视频课程,切出去回微信,小窗里只有视频,没有任何操作能力。
Document PiP:切出去回微信时,小窗里不只有视频,还有进度条、你自定义的笔记面板、甚至 AI 助教实时摘要。用户不需要切回来就能完成所有操作。
核心 API 就三个步骤
Document PiP 的门槛非常低,整个 API 可以浓缩成三步:
第一步:打开一个 PiP 窗口
const pipWindow = await documentPictureInPicture.requestWindow({
width: 400,
height: 300,
copyStyleSheets: true, // 自动把主窗口的 CSS 复制过去
});
requestWindow() 返回一个 Promise,resolve 后拿到的是新窗口的 Window 对象。注意:每个标签页同一时间只能有一个 Document PiP 窗口。
第二步:把内容塞进去
// 拿到你想浮动的那个 DOM 节点
const chatPanel = document.querySelector("#meeting-chat");
// 移动到 PiP 窗口的 body 里
pipWindow.document.body.append(chatPanel);
注意这里用的是「移动」而非「复制」——节点从主窗口消失,出现在小窗里。关闭 PiP 窗口时需要把它移回来。
第三步:监听关闭事件
pipWindow.addEventListener("pagehide", () => {
// 把节点移回主窗口
document.querySelector("#meeting-container").append(chatPanel);
});
这个 pagehide 事件在用户点击关闭按钮或 PiP 窗口被系统强制关闭时触发。配合 copyStyleSheets: true,移回去的节点样式完全一致,用户感知不到切换。
视频会议场景:这个能力终于完整了
Document PiP 最早被视频会议场景推起来的。用户在看演示文稿的同时要看到其他参会者的小头像——这是 WebRTC 应用里的刚需。
在 Document PiP 出现之前,开发者只能用 <canvas> 自己做视频拼接,或者干脆放弃这个能力。现在标准 API 就能实现:
// 把参会者画廊塞进 PiP 小窗
const gallery = document.querySelector("#participant-gallery");
const pipWindow = await documentPictureInPicture.requestWindow({
width: 320,
height: 240,
copyStyleSheets: true,
});
pipWindow.document.body.style.display = "flex";
pipWindow.document.body.style.flexWrap = "wrap";
pipWindow.document.body.style.gap = "4px";
pipWindow.document.body.append(gallery);
用户切换标签页去看参考资料时,视频会议的小窗依然在最上层,所有参会者头像+名字完整保留。这在以前要么做不到,要么需要几千行代码才能 workaround。
自动 PiP:视频会议的未来交互
Chrome 126 开始还支持了自动进入 PiP 的能力——用户切换标签页时,如果应用正在调用 getUserMedia(即摄像头/麦克风开着),浏览器可以自动打开 PiP 小窗而不需要用户主动点击。
这个能力需要三个前置条件:
- 页面注册了
navigator.mediaSession.setActionHandler("enterpictureinpicture", ...) - 页面正在 active 捕获摄像头或麦克风
- 用户在 Chrome 设置里开启了「自动画中画」
这对在线教育、远程医疗这类「用户需要边看资料边参会」的场景非常友好。用户切出去查文档,小窗自动出现;切回来,小窗自动消失。全程不需要用户手动操作。
浏览器支持:Firefox 也跟上了
目前状态:
- Chrome 116+:完全稳定,支持
copyStyleSheets和自动 PiP - Edge 116+:和 Chrome 同步
- Firefox 151+(2026年5月):正式支持
- Safari:暂无支持,桌面端 Safari 仍只支持传统
<video>PiP
Firefox 151 的加入意义重大——这意味着 Document PiP 真正成为了跨浏览器可用的标准能力,而不是 Chrome 专属。
对于 Safari 用户,建议做渐进增强:
if ("documentPictureInPicture" in window) {
// Document PiP 完整功能
enableDocumentPip();
} else if ("pictureInPictureEnabled" in document) {
// 降级到传统 video PiP
enableLegacyPip();
} else {
// 完全不支持,显示提示
showPipUnsupportedMessage();
}
三个容易踩的坑
坑1:每个标签页只能有一个 Document PiP 窗口
再次调用 requestWindow() 不会打开第二个窗口,而是返回已有窗口。所以如果要「替换」内容,正确的做法是先关闭再打开:
// 关闭已有的
if (documentPictureInPicture.window) {
documentPictureInPicture.window.close();
}
// 再打开新的
const newWindow = await documentPictureInPicture.requestWindow();
坑2:copyStyleSheets: true 对跨域样式表无效
这个选项只会复制同源 CSS。如果页面引用了 CDN 的样式表(字体、图标库等),小窗里这些样式会丢失。解法是手动同步关键样式,或者把关键 CSS 内联到文档里:
[...document.styleSheets].forEach(sheet => {
try {
const css = [...sheet.cssRules].map(r => r.cssText).join("");
const style = pipWindow.document.createElement("style");
style.textContent = css;
pipWindow.document.head.appendChild(style);
} catch {
// 跨域 sheet,跳过
}
});
坑3:PiP 窗口无法定位
requestWindow() 不接受 left/top 参数——浏览器自动把窗口放在屏幕角落,开发者无法控制精确位置。这在多显示器场景下可能出问题,用户不一定能看到小窗出现。
接下来可以做的三件事
第一件:打开 DevTools 控制台,执行 documentPictureInPicture.requestWindow() 看看能不能弹出一个小窗——这个能力在本地开发环境就能测试,不需要任何外部依赖。
第二件:找一个你正在做的视频应用(在线教育、视频会议、直播带货都行),把其中一个可交互面板(比如聊天区、问答区、白板)做成 Document PiP 浮动。这是目前最成熟、最实用的切入角度。
第三件:如果你的应用面向 Safari 用户,先实现传统 <video> PiP 降级方案——Safari 还不支持 Document PiP,但传统 PiP 已经稳定很多年了,用户体验比没有画中画要好得多。
画中画这个能力被「浪费」了好几年,根因就是传统 API 的能力边界太窄。Document PiP 把这个边界彻底打开了——它本质上是给浏览器增加了一个受控的子窗口,而不是视频播放器的附属功能。视频会议、在线教育、实时协作工具,这些场景都会因为这个 API 变得更自然。
评论区
登录后可评论。