Document Picture-in-Picture API: Full Tutorial and Implementation Guide
This article provides a comprehensive tutorial on the Document Picture-in-Picture (PiP) API, covering its purpose, browser support checks, window creation, style synchronization, event handling, cloning techniques, and a complete example with HTML, CSS, and JavaScript code.
Document Picture-in-Picture Introduction
The Document Picture-in-Picture (PiP) API allows any HTML content to be displayed in a floating window that stays on top of the screen, similar to video PiP but applicable to arbitrary elements.
Video PiP vs. Document PiP
Traditional video PiP works on platforms like Tencent Video and Bilibili, but Document PiP extends this capability to any DOM element, enabling flexible UI interactions.
Basic HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document Picture-in-Picture API 示例</title>
<style>
#pipContent {
width: 600px;
height: 300px;
background: pink;
font-size: 20px;
}
</style>
</head>
<body>
<div id="container">
<div id="pipContent">这是一个将要放入画中画的 div 元素!</div>
<button id="clickBtn">切换画中画</button>
</div>
<script>
// JavaScript will be added here
</script>
</body>
</html>Requesting a PiP Window
The core method is window.documentPictureInPicture.requestWindow , which returns a Promise that resolves to a new window object representing the PiP window.
document.getElementById("clickBtn").addEventListener("click", async function () {
const pipContent = document.getElementById("pipContent");
const pipWindow = await window.documentPictureInPicture.requestWindow({
width: 200,
height: 300
});
pipWindow.document.body.appendChild(pipContent);
});Checking Browser Support
if ('documentPictureInPicture' in window) {
console.log("🚀 浏览器支持 PiP 功能!");
} else {
console.warn("⚠️ 当前浏览器不支持 PiP 功能,更新浏览器或者换台电脑吧!");
}Synchronizing Styles
To make the PiP window look the same as the original page, copy all stylesheet rules or link tags into the PiP document.
// Copy CSS rules
[...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);
}
});Event Listeners for PiP
Listen for entering and exiting PiP, as well as focus/blur events.
// Enter event
documentPictureInPicture.addEventListener("enter", () => {
console.log("已进入 PIP 窗口");
});
// Exit event
pipWindow.addEventListener("pagehide", () => {
console.log("已退出 PIP 窗口");
});
// Focus / blur
pipWindow.addEventListener('focus', () => {
console.log("PiP 窗口进入了焦点状态");
});
pipWindow.addEventListener('blur', () => {
console.log("PiP 窗口失去了焦点");
});Cloning Elements
To keep the original element visible, clone it before appending to the PiP window.
const pipContent = document.getElementById("pipContent");
const pipWindow = await window.documentPictureInPicture.requestWindow({width:200,height:300});
pipWindow.document.body.appendChild(pipContent.cloneNode(true));Complete Example
The full working example combines all the above steps into a single HTML file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document Picture-in-Picture API 示例</title>
<style>
#pipContent { width:600px; height:300px; background:pink; font-size:20px; }
</style>
</head>
<body>
<div id="container">
<div id="pipContent">这是一个将要放入画中画的 div 元素!</div>
<button id="clickBtn">切换画中画</button>
</div>
<script>
if ('documentPictureInPicture' in window) {
console.log("🚀 浏览器支持 PiP 功能!");
} else {
console.warn("⚠️ 当前浏览器不支持 PiP 功能,更新浏览器或者换台电脑吧!");
}
document.getElementById("clickBtn").addEventListener("click", async function () {
const pipContent = document.getElementById("pipContent");
const pipWindow = await window.documentPictureInPicture.requestWindow({width:200,height:300});
pipWindow.document.body.appendChild(pipContent.cloneNode(true));
// Sync styles
[...document.styleSheets].forEach((styleSheet) => {
try {
const cssRules = [...styleSheet.cssRules].map(r=>r.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);
}
});
// Events
pipWindow.addEventListener('pagehide',()=>{console.log('已退出 PIP 窗口');});
pipWindow.addEventListener('focus',()=>{console.log('PiP 窗口进入了焦点状态');});
pipWindow.addEventListener('blur',()=>{console.log('PiP 窗口失去了焦点');});
});
</script>
</body>
</html>Conclusion
By following this guide, you can leverage the Document Picture-in-Picture API to float any HTML element, synchronize its styles, and handle lifecycle events, enabling richer interactive experiences on modern browsers.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.