浏览器中的画中画(Picture-in-Picture)模式及其 API

简介:

想边刷微博边追剧?想边聊微信边看球赛?从浏览器支持扩展功能开始,人们就一直有这样的需求:

Chrome看视频,有没有可以弹出视频窗口的插件?

各个国产壳子浏览器也争相内置“视频弹窗播放”的功能,比如当年的火狐中国版

2700061cbfe5f04bc6812c6d370d967c92eaeadc

这么多年过去了,正统浏览器们终于要内置这个功能了,而且还有配套的 API 给开发者使用。

WICG,全名为 Web Incubator Community Group(Web 孵化器社区小组),主要成员为 Chrome 的工程师们,他们从一年前开始标准化这个能让视频弹窗播放的特性,起名为 Picture-in-Picture(画中画),缩写为 PiP。

Chrome 从今年年初开始着手实现,到本文撰稿时,已经实现的差不多了。这篇文章将主要讲两方面:Chrome 当前实现的 PiP 交互是怎么样的,以及有哪些 API 让我们开发者使用。

Chrome 中的 PiP 交互

Chrome 官方提供了一个 demo 页面 Picture-in-Picture Sample,我用这个 demo 录了一个简单的演示视频:


从视频中可以看到,Chrome 在原生的 video 控件中提供了开启画中画模式的菜单项,一旦开启画中画模式,原本页面中内联(inline)展现的那个 video 还占据着原来的位置,各种控件也都在,但最重要的视频画面已经被无缝的转移到了新的弹出窗口中了,只剩下一张 poster 图片和一层灰色的遮罩。

我们把弹出的那个视频窗口叫做 PiP 窗口,PiP 窗口只有视频画面,没有标题栏和地址栏(chrome-less),这一点和用 window.open()打开的弹窗不一样。同时,PiP 窗口也没有完整的视频控件,只有开始/暂停/关闭按钮三个,时间、进度条、音量这些控件都没有。PiP 窗口还支持拖拽改变大小(不能大于一个象限),以及支持拖拽到任意位置(录屏里没有体现,因为在本文撰写时还不支持)。还有最重要的一点是,PiP 窗口在所有窗口中是置顶的(always on top),正如我在录屏里演示的,当焦点切换到 Safari 后,Chrome 中打开的 PiP 窗口仍然是在最上层的。

另外一个没有在录屏里体现出来的交互是,“同一时刻只能有一个 PiP 窗口”。同一个页面里如果为多个视频开启画中画模式,前面开启的那个会自动退出画中画模式,同一个浏览器窗口下的多个 Tab 里的视频亦如此,同一个浏览器打开的多个浏览器窗口亦如此(在本文撰稿时,Chrome 还没有实现最后一种情况,即多个浏览器窗口可以同时开启多个 PiP 窗口,已确认是 bug 不是 feature)。

PiP 相关 API

1. video 元素新增的方法 requestPictureInPicture()

请求让该 video 元素进入画中画模式,返回一个 promise,如果没有异常,这个 promise 包的值会是一个 PictureInPictureWindow对象,这个对象就代表弹出的那个 PiP 窗口,后面会单独讲它的 API。


async function openPiP(video) {
  try {
    const pipWindow = await video.requestPictureInPicture() // 进入画中画模式
    ...
  } catch (e) {
    console.error(e) // 处理异常
  }
})

哪些情况下进入画中画模式会失败?一共有 5 种情况:

  1. 操作系统不支持、或者用户通过浏览器选项禁用了此功能,此时 document.pictureInPictureEnabled 属性会返回 false
  2. 视频文件错误、或者没有视频流只有音频流
  3. 此次请求不是由用户操作触发的,比如用户没有点击任何按钮,页面自动执行该方法,会被当做恶意行为拦截掉
  4. 当前页面通过 feature-policy 禁用了画中画特性,此时 document.pictureInPictureEnabled属性也会返回 false
  5. 当前 video 元素通过 disablePictureInPicture 属性(HTML 属性和 DOM 属性均可)禁用了画中画特性

2. video 元素新增的属性 disablePictureInPicture

通过该属性可以禁用 video 元素的画中画特性,右键菜单中的“画中画”选项会被禁用。

通过 HTML 属性:

<video src="..." disablePictureInPicture>

通过 DOM 属性:

video.disablePictureInPicture = true

3. video 元素新增的事件 enterpictureinpicture 和 leavepictureinpicture


video.addEventListener('enterpictureinpicture', function(pipWindow) {
  // 进入了画中画模式,可以拿到 pipWindow 对象
})

video.addEventListener('leavepictureinpicture', function() {
  // 退出了画中画模式
})

4. document 上新增的方法 exitPictureInPicture()

因为一个页面只能打开一个 PiP 窗口,所以让 video 元素退出画中画模式的方法不在 video 元素自己身上,而在 document 上。

这个方法也返回一个 promise,不过 promise 包的值是个 undefined

5. document 上新增的属性 pictureInPictureElement和 pictureInPictureEnabled

类似于document.pointerLockElement和 document.fullscreenElement, document.pictureInPictureElement 会返回当前页面中处于画中画模式的 video 元素,如果没有的话,返回 null

document.pictureInPictureEnabled上面已经提到过了,在当前页面不支持或被禁用画中画模式的情况下会返回 false,否则返回 true

这两个属性都是只读的。

6. PictureInPictureWindow对象的 API

requestPictureInPicture()方法的返回值和 enterpictureinpicture事件的回调参数中可以拿到 pipWindow 对象,该对象有两个属性 widthheight,还支持一个resize事件,在用户改变 PiP 窗口大小时会触发。


async function openPiP(video) {
  const pipWindow = await video.requestPictureInPicture()
  console.log(pipWindow.width, pipWindow.height) // 打印了默认的窗口大小

  pipWindow.addEventListener('resize', function() {
    console.log(pipWindow.width, pipWindow.height) // 用户改变 PiP 窗口大小时触发
  })
}

注意这里的 widthheight是只读的,你不能通过给他们赋值来改变窗口大小。

杂项

1. Safari 中已有的画中画 API

Safari 在两年前就支持了画中画模式,还有一套带前缀的配套 API,叫 Presentation Mode。好消息是这个新规范也有 Safari 的人参与了制定,事实上目前为止四大浏览器厂商只剩 Edge 还没表示支持。

2. 画中画这个名字的由来

“画中画”这东西是十几年前电视机上的一个功能,我自己去年看到这个规范的时候也觉的它这个名字比较误导人,现在规范 issue 里也有个人在问,希望你没把它理解成是嵌套的 <img>

3. Chrome 哪个版本支持

现在的 Chrome Canary(69)还没有默认打开这个特性,需要你手动开启

chrome://flags/#enable-experimental-web-platform-features

chrome://flags/#disable-background-video-track

chrome://flags/#enable-picture-in-picture

这三个开关,不用 Canary 的同学老实等两个月。

4. 可不可能弹出 video 以外的元素

规范制定者表示未来有可能


原文发布时间为:2018年06月21日
原文作者: 掘金

本文来源: 掘金 如需转载请联系原作者

相关文章
|
存储 前端开发 开发者
|
Web App开发 iOS开发 MacOS
如何在浏览器中启用夜间模式?
【10月更文挑战第10天】
|
缓存 监控 API
探索微服务架构中的API网关模式
【10月更文挑战第5天】随着微服务架构的兴起,企业纷纷采用这一模式构建复杂应用。在这种架构下,应用被拆分成若干小型、独立的服务,每个服务围绕特定业务功能构建并通过HTTP协议协作。随着服务数量增加,统一管理这些服务间的交互变得至关重要。API网关作为微服务架构的关键组件,承担起路由请求、聚合数据、处理认证与授权等功能。本文通过一个在线零售平台的具体案例,探讨API网关的优势及其实现细节,展示其在简化客户端集成、提升安全性和性能方面的关键作用。
316 2
|
存储 缓存 监控
探索微服务架构中的API网关模式
【10月更文挑战第1天】探索微服务架构中的API网关模式
298 2
|
机器学习/深度学习 算法 数据挖掘
淘宝 API 开启天猫店铺客户流失预警新模式
在竞争激烈的电商市场中,天猫店铺面临客户流失的挑战。淘宝新推出的API为客户流失预警提供了创新解决方案,通过数据分析和机器学习,帮助商家识别潜在流失客户并及时干预,从而提升客户留存率、优化营销成本,助力店铺高效运营与可持续增长。
|
数据采集 Web App开发 存储
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
本文介绍了基于无界面浏览器(如ChromeDriver)和代理IP技术的现代爬虫解决方案,以应对传统爬虫面临的反爬机制和动态加载内容等问题。通过Selenium驱动ChromeDriver,并结合亿牛云爬虫代理、自定义Cookie和User-Agent设置,实现高效的数据采集。代码示例展示了如何配置ChromeDriver、处理代理认证、添加Cookie及捕获异常,确保爬虫稳定运行。性能对比显示,Headless模式下的ChromeDriver在数据采集成功率、响应时间和反爬规避能力上显著优于传统爬虫。该方案广泛应用于电商、金融和新闻媒体等行业。
892 0
深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作
|
存储 API 数据库
如何使用 ef core 的 code first(fluent api)模式实现自定义类型转换器?
本文介绍了如何在 EF Core 的 Code First 模式下使用自定义类型转换器实现 JsonDocument 和 DateTime 类型到 SQLite 数据库的正确映射。通过自定义 ValueConverter,实现了数据类型的转换,并展示了完整的项目结构和代码实现,包括实体类定义、DbContext 配置、Repositories 仓储模式及数据库应用迁移(Migrations)操作。
483 6
如何使用 ef core 的 code first(fluent api)模式实现自定义类型转换器?
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
缓存 监控 API
探索微服务架构中的API网关模式
随着微服务架构的兴起,API网关成为管理和服务间交互的关键组件。本文通过在线零售公司的案例,探讨了API网关在路由管理、认证授权、限流缓存、日志监控和协议转换等方面的优势,并详细介绍了使用Kong实现API网关的具体步骤。
295 3
|
存储 缓存 监控
探索微服务架构中的API网关模式
探索微服务架构中的API网关模式
249 2

热门文章

最新文章