Chrome 116 作为Google浏览器的最新稳定版本已正式发布。Chrome 浏览器支持视频画中画(HTMLVideoElement)已有一段时间,而 Chrome 116 则新增了文档画中画模式。这种"文档画中画"模式提供了一个始终在顶部的窗口,可以填充任意 HTML 元素。因此,它可以为视频内容提供更丰富的体验,也可用于其他目的。
例如,它可用于在显示视频画中画内容的同时显示文本或聊天信息和其他内容,也可用于显示广告。
Chrome 116 还增加了显示和内容可见性动画、对 Fetch API 的 BYOB 支持、CSS 运动路径以及其他各种开发人员新增功能。
Chrome 浏览器发布博客还介绍了 Chrome 116 中的许多安全修复。
同时,Chrome 浏览器 117 正在添加 CSS 叠加属性、不安全下载警告、添加 CSS 网格布局模块二级(subgrid)以及大量其他开发人员添加的内容,这些内容将在 9 月份以稳定版的形式发布。
Web API 接口参考 | MDN
比较值得关注的新增功能就是网页的画中画 API 了(Document Picture in Picture API
)。
画中画 API
可以打开一个始终位于当前网页顶部的窗口,这个窗口可以填充任意的 HTML
内容。它扩展了现有的 Picture-in-Picture API for
(其只允许将 元素放入画中画窗口中)。
通过 Document Picture-in-Picture API
创建的 Picture-in-Picture
窗口其实很类似于通过 window.open()
打开的空白的同源窗口,但也存在一些差异:
画中画窗口永远会浮动在其他窗口之上。
当前窗口关闭后会立即关闭打开的画中画窗口
无法通过地址导航到画中画窗口。
画中画窗口的位置无法由网站设置。
这个 API 还是有挺多实用场景的,首先我们还是可以用它来实现自定义视频播放器,虽然现有的 Picture-in-Picture API for
也可以实现,但是效果非常有限(参数少,样式设置灵活)。现在通过新的画中画 API,网站可以提供一些自定义组件和参数(例如字幕、播放列表、时间控制、喜欢和不喜欢的视频),来改善用户的画中画视频体验。另外我们还可以用它来实现一个体验非常好的网页视频会议功能等等。
documentPictureInPicture.window
:返回当前的画中画窗口,如果不存在则返回 null
。
documentPictureInPicture.requestWindow(options)
:返回一个在画中画窗口打开时解析的 Promise
。如果在没有用户同意的情况下调用它, Promise
将被拒绝。options
包括两个参数:
width
:设置画中画窗口的初始宽度。
height
:设置画中画窗口的初始高度。
documentPictureInPicture.onenter
:documentPictureInPicture
打开画中画窗口时触发。
手下我们通过下面的 HTML
设置自定义视频播放器和按钮元素以在画中画窗口中打开视频播放器。
当用户单击按钮打开空白的画中画窗口时,下面的 JavaScript
会调用documentPictureInPicture.requestWindow()
,然后返回的 promise
使用一个画中画窗口 JavaScript
对象进行解析。然后使用 append()
将视频播放器移动到该窗口。
pipButton.addEventListener('click', async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window.
const pipWindow = await documentPictureInPicture.requestWindow();
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
});
我们可以通过 width
和 height
属性来设置画中画窗口的大小。(如果选项值太大或太小而无法适应用户友好的窗口大小,Chrome
可能会限制选项值)
pipButton.addEventListener("click", async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window whose size is
// the same as the player's.
const pipWindow = await documentPictureInPicture.requestWindow({
width: player.clientWidth,
height: player.clientHeight,
});
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
});
要从原始窗口复制所有 CSS
样式表,我们可以循环遍历 styleSheets
文档中显式链接或嵌入的 CSS
样式表,并将它们附加到画中画窗口。
pipButton.addEventListener("click", async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window.
const pipWindow = await documentPictureInPicture.requestWindow();
// Copy style sheets over from the initial document
// so that the player looks the same.
[...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);
}
});
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
});
我们可以侦听窗口的 "pagehide"
事件来了解画中画窗口的关闭时机(网站启动它或用户手动关闭它)。事件处理程序是将元素从画中画窗口中取出的好地方,如下所示。
pipButton.addEventListener("click", async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window.
const pipWindow = await documentPictureInPicture.requestWindow();
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
// Move the player back when the Picture-in-Picture window closes.
pipWindow.addEventListener("pagehide", (event) => {
const playerContainer = document.querySelector("#playerContainer");
const pipPlayer = event.target.querySelector("#player");
playerContainer.append(pipPlayer);
});
});
使用 close()
方法可以直接关闭画中画窗口。
// Close the Picture-in-Picture window programmatically.
// The "pagehide" event will fire normally.
pipWindow.close();
我们可以监听 documentPictureInPicture
的 "enter"
事件来感知画中画窗口何时打开。这个事件包含一个用于访问画中画窗口的 window
对象。
documentPictureInPicture.addEventListener("enter", (event) => {
const pipWindow = event.window;
});
我们可以从 documentPictureInPicture. requestwindow()
返回的对象或使用 documentPictureInPicture
访问画中画窗口中的元素:
const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
// Mute video playing in the Picture-in-Picture window.
const pipVideo = pipWindow.document.querySelector("#video");
pipVideo.muted = true;
}
要检查是否支持文档画中画 API,可以使用:
if ('documentPictureInPicture' in window) {
// The Document Picture-in-Picture API is supported.
}
参考:
https://developer.chrome.com/docs/web-platform/document-picture-in-picture
https://developer.chrome.com/blog/watch-video-using-picture-in-picture/
https://developer.mozilla.org/docs/Web/API/Window/open
https://developer.mozilla.org/docs/Web/API/Element/append
https://lazy-guy.github.io/tomodoro/index.html