浏览器能浮个视频出去,但浮个小组件出去这件事从来没做过——Firefox 151 今天把它原生化了

浏览器能浮个视频出去这件事,Chrome 2019 年就做了。但浮个小组件出去——比如把页面右上角的股票行情、待办事项、聊天面板拆出来,让它始终悬在桌面最上层——这件事从来没被原生支持过。

Firefox 151 说:我把它做出来了。

什么是 Document Picture-in-Picture

传统 Picture-in-Picture(PiP)只能锁定一个 <video> 元素。Document PiP 不一样——它可以在桌面层打开一个空白窗口,然后把任意 HTML 结构装进去。这个窗口是真正独立的浏览器窗口:可以拖动、可以调整大小、可以放在任何桌面上、切换标签页和切换应用都影响不了它。

实际应用场景很具体:股票行情实时浮窗、跨标签页的待办面板、视频会议的浮动控件、播放列表、实时协作编辑的小面板——这些以前要么靠 Electron 桌面应用,要么靠浏览器扩展,要么靠各种 hack 实现,现在一个 API 搞定。

浏览器支持现状

Chrome 116+ 和 Edge 116+ 早就有了。Firefox 151(2026 年 9 月)刚刚加入。Safari 还在排队,Can I Use 数据显示全球约 26% 覆盖,移动端完全不支持。需要 @supports 做渐进增强?别想了——这个 API 没有对应的 CSS feature query,at-rule() 函数只有 Chrome 支持,而且 WICG 已经把 display-mode: picture-in-picture 的支持计划撤回了。只能用 JavaScript 检测:

if (!(“documentPictureInPicture” in window)) {
// 不支持,移除按钮或做降级
document.querySelector(“.pip-button”).remove();
}

最小可运行例子

三步走:检测支持 → 打开窗口 → 把内容移进去。

第一步,检测:

const pipButton = document.querySelector(“.pip-button”);

pipButton.addEventListener(“click”, async () => {
if (!(“documentPictureInPicture” in window)) return;
});

第二步,打开窗口:

const pipWindow = await window.documentPictureInPicture.requestWindow({
width: 400,
height: 300
});

第三步,把目标元素移进去:

const widget = document.querySelector(“.my-widget”);
pipWindow.document.body.append(widget);

这样点一下按钮,你的 .my-widget 就从页面里消失了,出现在一个独立的浮动窗口里。

样式迁移:坑在这里

新开的 DPIP 窗口是空白的——没有任何样式。CSS 不会跟着元素一起过来,需要手动复制。

标准做法是用 createDocumentFragment 把所有样式表一次性移过去,避免多次 reflow:

const styles = Array.from(document.querySelectorAll(
‘link[rel=”stylesheet”]’, ‘style’
));

const fragment = document.createDocumentFragment();
styles.forEach(s => fragment.appendChild(s.cloneNode(true)));
pipWindow.document.head.appendChild(fragment);

然后给 DPIP 窗口里的内容写针对性的 CSS,用 @media (display-mode: picture-in-picture) 媒体查询:

@media (display-mode: picture-in-picture) {
.my-widget {
padding: 12px;
font-size: 14px;
}
}

还有一个坑:事件监听器

把元素移进 DPIP 窗口后,元素上的事件监听器不会自动跟随。需要重新绑定,或者用事件委托:

pipWindow.document.addEventListener(“click”, (e) => {
if (e.target.matches(“.my-widget .close-btn”)) {
pipWindow.close();
}
});

键盘焦点问题

打开 DPIP 窗口会抢走键盘焦点——你按 Ctrl+T 想开新标签,焦点可能被 DPIP 窗口截走。关掉 DPIP 或者先点一下标签栏还回来。WICG 已有 issue 追踪。

标题栏无法隐藏

出于安全考虑,DPIP 窗口的标题栏永远带着网站来源标识和关闭按钮——这是浏览器强制要求,防止钓鱼。可以用 disallowReturnToOpener 选项隐藏”返回原标签”按钮,但标题栏本身无法去掉。

能不能全屏

不能。requestFullscreen() 在 DPIP 窗口里被明确禁用,WICG Issue #133 已写入规范。

现在能不能用

能用,但要做降级:

async function openPip() {
if (!(“documentPictureInPicture” in window)) {
window.open(url, “widget”, “width=400,height=300”);
return;
}

const pipWindow = await documentPictureInPicture.requestWindow();
}

在 Chrome + Firefox 上这个 API 已经很稳。团队里如果有 Safari 用户,需要告诉他们这个功能暂时用不了,不要误以为是 bug。

下一步

如果你在做一个有可拆分小组件的产品——股票、待办、聊天、实时数据面板——现在可以用 Document PiP 做一个无依赖的浮动窗口版,不需要 Electron,不需要扩展,不需要 Service Worker。三步检测 + requestWindow + cloneNode,今天下午就能跑通 Demo。

评论区

0 条评论

登录后可评论。