前端实现视频画中画功能 - 主页面与小窗同步控制
如何使用 Document Picture-in-Picture API 在前端实现视频画中画功能。通过创建独立的小窗口播放视频,并实现主页面与小窗之间的播放状态、进度、音量等双向同步。提供了完整的 HTML、CSS 和 JavaScript 代码示例,适用于自定义播放器场景,提升了多任务处理下的视频观看体验。

如何使用 Document Picture-in-Picture API 在前端实现视频画中画功能。通过创建独立的小窗口播放视频,并实现主页面与小窗之间的播放状态、进度、音量等双向同步。提供了完整的 HTML、CSS 和 JavaScript 代码示例,适用于自定义播放器场景,提升了多任务处理下的视频观看体验。

不知道小伙伴是否发现 B 站的视频播放中,有一个功能 画中画 ,当用户点击会展现一个小窗播放,即使将主窗口缩起来,小窗口依然保留在外面电脑桌面上。
开启画中画(小窗口)

收缩主窗口

随着 Chrome 116+ 支持 Document Picture‑in‑Picture API 的出现,我们终于可以把整个页面内容(不仅仅是 <video>)移入画中画小窗口中,并在小窗中实现自定义控件、播放进度操作等功能。
本文博主将带着小伙伴们实现一个主页面和小窗同步视频控制功能,例如在主窗口暂停、小窗也同步暂停;调节音量、跳转进度也保持一致,提升用户体验。
在当今多任务处理的时代,用户经常需要在观看视频的同时进行其他操作(如浏览信息、回复消息等)。小窗模式(画中画)解决了这一需求,让视频可以浮动在页面上方,同时用户可以自由浏览其他内容。
与传统 Picture-in-Picture 的区别

<video> 的画中画 API 功能有限,无法带自定义控件与交互API 可以让整个文档出现在独立的小窗口中,支持丰富交互,如播放、暂停、音量、进度条等新
API优势
完整 HTML 支持:可包含按钮、进度条等交互元素
无缝集成:与原始页面共享 JavaScript 上下文
尺寸灵活:可自定义小窗尺寸
双向通信:主页面与小窗实时同步
代码中 1.mp4 为博主本地保存测试的视频,大家可以自行获取相应资源源,修改 video 的 src 即可
*{margin: 0;padding: 0;box-sizing: border-box;}body{font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.6;color: #333;background:linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);padding: 20px;min-height: 100vh;}.container{max-width: 1200px;margin: 0 auto;background-color:rgba(255, 255, 255, 0.95);border-radius: 15px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);overflow: hidden;}header{background:linear-gradient(to right, #1a2a6c, #b21f1f);color: white;padding: 25px 40px;text-align: center;}h1{font-size: 2.5rem;margin-bottom: 10px;text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);}.subtitle{font-size: 1.2rem;opacity: 0.9;max-width: 700px;margin: 0 auto;}.content{display: flex;padding: 30px;gap: 30px;}.video-section{flex: 3;background: #f8f9fa;border-radius: 10px;overflow: hidden;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);}.video-container{position: relative;padding-top: 56.25%;/* 16:9 Aspect Ratio */background: #000;}video{position: absolute;top: 0;left: 0;width: 100%;height: 100%;display: block;}.video-controls{display: flex;padding: 15px;gap: 10px;background: #e9ecef;}button{background: #1a2a6c;color: white;border: none;padding: 10px 20px;border-radius: 5px;cursor: pointer;font-weight: 600;transition: all 0.3s ease;display: flex;align-items: center;gap: 8px;}button:hover{background: #0d1a4d;transform:translateY(-2px);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);}button:disabled{background: #6c757d;cursor: not-allowed;transform: none;box-shadow: none;}.info-section{flex: 2;background: white;padding: 25px;border-radius: 10px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);}h2{color: #1a2a6c;margin-bottom: 20px;padding-bottom: 10px;border-bottom: 2px solid #e9ecef;}.feature-list{margin: 20px 0;}.feature{display: flex;align-items: flex-start;margin-bottom: 15px;}.feature-icon{background: #1a2a6c;color: white;width: 30px;height: 30px;border-radius: 50%;display: flex;align-items: center;justify-content: center;margin-right: 15px;flex-shrink: 0;}.pip-window{position: fixed;bottom: 20px;right: 20px;width: 300px;height: 200px;background: black;border-radius: 10px;overflow: hidden;box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);z-index: 1000;display: none;}.pip-window video{width: 100%;height: 100%;object-fit: cover;}.pip-controls{position: absolute;bottom: 10px;left: 0;right: 0;display: flex;justify-content: center;gap: 10px;opacity: 0;transition: opacity 0.3s;}.pip-window:hover .pip-controls{opacity: 1;}.status{padding: 15px;background: #e9ecef;border-radius: 8px;margin-top: 20px;font-family: monospace;}.browser-support{margin-top: 30px;padding: 20px;background: #fff8e1;border-radius: 8px;border-left: 4px solid #ffc107;}.support-list{display: flex;gap: 15px;margin-top: 15px;flex-wrap: wrap;}.browser{display: flex;align-items: center;gap: 8px;}.supported{color: #28a745;}.unsupported{color: #dc3545;}@media(max-width: 900px){.content{flex-direction: column;}}
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>视频小窗模式演示</title><link href="css/pip.css" rel="stylesheet" type="text/css"/></head><body><div class="container"><header><h1>视频小窗模式演示</h1><p class="subtitle">使用 Document Picture-in-Picture API 实现在其他内容上浮动播放视频</p></header><div class="content"><div class="video-section"><div class="video-container"> 开启小窗模式 全屏 Document Picture-in-Picture API1任意 HTML 内容可以在小窗中显示视频控件、字幕等任意 HTML 元素2保持播放状态进入小窗模式时视频持续播放,不中断观看体验3双向同步主页面和小窗中的视频状态实时同步4自由调整用户可以调整小窗位置和大小,适应不同需求当前状态:等待操作小窗状态:未激活浏览器支持情况Chrome 108+FirefoxEdgeSafari关闭
小伙伴们可以根据以下 GIF 演示图,查看效果
documentPictureInPicture.requestWindow({ width, height }) 创建 PiP 窗口<video> 的 DOM 节点移动到小窗口中pagehide 或按钮将 DOM 恢复到主窗口
Document Picture-in-Picture API 为开发者提供了强大的工具来创建更灵活的视频观看体验。虽然目前浏览器支持有限(Chrome 116+),但随着标准的发展,相信它将成为视频播放页面的标配功能。
本文演示了如何使用 window.documentPictureInPicture.requestWindow() API 创建一个自定义画中画窗口,并实现主窗口与小窗之间同步播放、暂停、音量控制与关闭逻辑。该方案相比传统 PiP 能实现更强的可定制化,适用于自定义播放器场景。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online