H5 中很多场景交互较少强调动画展示的场景都可以借助视频实现,而且能够实现 100% 视觉还原😝,对于设计师来说最终呈现效果可控,对开发来说极大地降低了工作量,运营因为工期减少也会开心,简直是一石三鸟的事情!不过移动端 video 还是有很多坑的,以下是我做的一点调研。
去除 video 的播放控件
video 标签不设置 control
属性,在 iOS 与 Android 上也会出现播放控件,并且视屏元素的层级调整到最高,上方不能覆盖有其他元素。
Canvas 方案
可使用 pixi.js 播放 video 的功能,将视频画面用 Canvas 输出。
let app = new PIXI.Application({
view: document.getElementById('stage'),
forceCanvas: true,
});
// create a video texture from a path
let texture = PIXI.Texture.fromVideo(require('assets/video/video.mp4'));
// create a new Sprite using the video texture (yes it's that easy)
let videoSprite = new PIXI.Sprite(texture);
app.stage.addChild(videoSprite);
该方式在 iOS 高德端内还是会展示播放控件,至于 Android 端内表现良好,但是因为前者的问题所以该方案还是被舍弃了。
CSS 样式
非移动端直接去除 control
属性即可,但是移动端仅仅依靠这是不行的。
至于移动端这里还得分情况,Android 上的 Chrome 其实只需不声明 control
属性即可。即便申明了用如下 CSS 也可移除播放控件。
video::-webkit-media-controls-panel {
display:none !important;
}
iOS 上的 Safari 上的播放控件貌似是无法使用 CSS 隐藏掉的,需去除 control
属性,但是只要播放后还是会进入全屏模式,这时候需要添加 playsinline
,不过这种方案与 CSS 没啥关系了。
所以单纯依靠 CSS 去除播放控件也是不可行的,其余端的测试也没继续下去。
iOS 微信端内
使用 playsinline="true"
与 webkit-playsinline="true"
属性可以使视频内联播放。iOS 10 以及之后的版本支持 playsinline="true"
,iOS 10 之前的版本可使用webkit-playsinline="true"
。
具体参考 Webkit 官方文章: New <video> Policies for iOS
<video src="video.mp4"
playsinline="true"
webkit-playsinline="true"
></video>
如动态添加 playsinline
与 webkit-playsinline
无效,需提前在 HTML 中定义好。上述属性配置需 iOS 中 WebView 中需要有相应的设置支持,否者前端已经设置上述属性也是无效的。
iOS 高德端内
使用 enableInlineVideo
插件,可实现端内无控件播放。
<video src="video.mp4"
id="video"
playsinline="true"
webkit-playsinline="true">
</video>
<script>
let video = document.querySelector('#video');
video.play();
enableInlineVideo(video);
</script>
<style lang="scss">
.IIV::-webkit-media-controls-play-button,
.IIV::-webkit-media-controls-start-playback-button {
opacity: 0;
pointer-events: none;
width: 5px;
object-position: center center;
}
</style>
Android 高德端内
目前各个方案都能很好的隐藏播放控件。
Android 微信端内
腾讯浏览器 X5 内核 提供了 H5 同层播放器接入规范,由于微信内置浏览器使用的是腾讯浏览器 X5 内核,可使用其一些私有属性。
x5-video-player-type
通过 video 属性 x5-video-player-type
声明启用同层 H5 播放器。
<video src="http://xxx.mp4" x5-video-player-type="h5"/>
这个属性需要在播放前设置好,播放之后设置无效。
x5-video-player-fullscreen
x5-video-player-fullscreen
可使视频播放时进入到全屏模式。如果不申明此属性,页面得到视口区域为原始视口大小(视频未播放前),比如在微信里,会有一个常驻的标题栏,如果不声明此属性,这个标题栏高度不会给页面,播放时会平均分为两块(上下黑块)。
<video id="video" src="xxx" x5-video-player-type="h5" x5-video-player-fullscreen="true"/>
声明此属性,需要页面自己重新适配新的视口大小变化。可以通过监听resize 事件来实现。
window.onresize = function(){
video.style.width = window.innerWidth + "px";
video.style.height = window.innerHeight + "px";
}
同样,这个属性需要在播放前设置好,播放之后设置无效。
控件隐藏测试结果
机型 | 高德端内 | 微信端内 | 说明 |
---|---|---|---|
iPhone 8 Plus | ✔️ | ✔️ | |
iPhone X | ✔️ | ✔️ | |
Galaxy Note 4 | ✔️ | ✔️ | |
红米 Note 4 | ✔️ | ✔️ | |
魅族 Pro 6 | ✔️ | ✔️* | Title Bar 透明 |
Galaxy S6 edge | ❌ | ❌ | 高德 App 会自动假死退出,无法完成测试 |
特殊机型问题
魅族 Pro 6
魅族 Pro 6 在微信端内会新开一个层展示视频,且标题栏会变透明,去除属性 x5-video-player-fullscreen
也无效。
自动播放
与音频一样,视屏播放也需要用户的操作来触发,通过一些按钮来诱导用户触发视频播放。
let videoPlay = () => {
video.play();
document.removeEventListener('touchstart', videoPlay);
};
document.addEventListener('touchstart', videoPlay, false);
检测是否支持自动播放
play()
方法会返回一个 promise,如果无法播放会抛出一个错误,可以被 catch 到。
video.play().catch((error) => {
// do something error handler
});
iOS
iOS 上的 Safari 视频自动播放
iOS 10 中允许自动视频播放的两种情况:
- 无音轨视频
- 无声音视频(设置了
muted
属性) - 视频元素需在是视口内且是可见的
- 视频元素需插入到 DOM 中
Android
Android Chrome
Chrome 53 之后也支持了 iOS Safari 同样的策略,无音轨或者静音的视频可以自动播放。
<video autoplay muted>
<source src="video.webm" type="video/webm" />
<source src="video.mp4" type="video/mp4" />
</video>
Android 其他浏览器
Firefox 和 UC 浏览器已经在 Android 上支持自动播放,无论是否静音,它们不会阻止任何类型的自动播放。未验证
Android 高德端内
在 875 之后介入了 UC WebView,本以为可以实现同 UC 的策略但是测试。不可以自动播放,需用户手动触发。
iOS 与 Android 微信端内
在微信中集成 JS-SDK 后监听 WeixinJSBridgeReady
事件可触发视频播放,可无需经由用户操作从而实现音乐播放的目的,因该是微信内部做了处理。
document.addEventListener(
'WeixinJSBridgeReady',
function() {
video.play();
},
false
);
预加载
如视频播放因资源未加载完毕而造成的卡顿会影响体验,需预先加载好视频文件。在PC 端可用 preload="auto"
属性实现视频的预加载。但 iOS 中 preload="auto"
属性是不生效的,可支持proload="metadata"
到,同样的策略在 Android Chrome 也适用。
preload
尝试使用 preload
可以实现资源预加载,其其实是一个声明形的 fetch
,可以强制浏览器在不阻塞 document
的 onload
事件的情况下请求资源,即强制提升视频文件的优先级。通过 Can I Use 查询 preload,iOS 11.3 与 Chrome 67 之后才开始支持。
<link rel="preload" href="video.mp4" as="video" type="video/mp4" onload="handleVidoeLoaded">
<video id="video"></video>
<script>
function handleVidoeLoaded() {
const video = document.getElementById("video");
video.src = 'video.mp4';
}
</script>
也通过 JavaScript 动态添加 video 预加载:
let link = document.createElement('link');
link.setAttribute('rel', 'preload');
link.setAttribute('href', 'video.mp4');
link.setAttribute('as', 'video');
link.setAttribute('type', 'video/mp4');
link.addEventListener('load', handleVideoLoaded)
document.head.appendChild(link);
// ...
经过测试该方式并不能提前预加载视频文件
XMLHTTPRequest
Google Developer 中介绍使用 Fetch 手动缓冲视频文件的方法,借助这个思路,同理使用 XMLHTTPRequest
先将视频文件加载到本地,然后给 video 元素的 src 属性赋值。
const { video } = this.$refs;
const self = this;
const req = new XMLHttpRequest();
req.open('GET', `video.mp4?t=${new Date() * 1}`, true);
req.responseType = 'blob';
req.onload = () => {
if (req.readyState === 4) {
if (req.status === 200) {
const videoBlob = req.response;
const vid = URL.createObjectURL(videoBlob);
video.src = vid;
}
}
};
req.onerror = () => {
// Error
};
req.onprogress = () => {
};
req.send();
机型测试
本次测试高的端内为 850 以及以上版本,为 UC 内核。
- 视频无音轨或者为 muted
- 使用
iphone-inline-video
- 视频位于页面可见范围内
高德端内
系统 | 系统版本 | 机型 | 自动播放1 | 无播放控件 | 可被覆盖 | 备注 |
---|---|---|---|---|---|---|
iOS | 11.41 | iPhone 8 Plus | ✔️ | ✔️ | ✔️ | |
12.01 | iPhone 6 | ✔️ | ✔️ | ✔️ | ||
Android | 6.0 | 红米 Note 4 | ✔️ | ✔️ | ✔️ | |
8.0 | 华为 Meta 9 | ✔️ | ✔️ | ✔️ | 播放延迟2 | |
7.0 | 小米 Max | ✔️ | ✔️ | ✔️ | ||
8.1 | 华为 P20 | ✔️ | ✔️ | ✔️ | ||
8.1 | 华为 Meta 10 Pro | ✔️ | ✔️ | ✔️ | ||
7.0 | Moto Z Play | ✔️ | ✔️ | ✔️ |
微信端内
系统 | 系统版本 | 机型 | 平台 | 自动播放 | 播放控件 | 可被覆盖 | 备注 |
---|---|---|---|---|---|---|---|
iOS | 12.01 | iPhone 6 | 微信端内 | ✔️ | ✔️ | ✔️ | |
Android | 6.0 | 红米 Note 4 | 微信端内 | ✔️ | ✔️ | ✔️ |
参考
- 视频H5 video标签最佳实践
- 如何制作一个完美的全屏视频H5
- 视频H5のVideo标签在微信里的坑和技巧
- HTML canvas video player
- Fast Playback with Video Preload
- Creating A Custom HTML5 Video Player And The Shadow DOM
- Using <video> and <audio>
- Optimizing MP4 Video for Fast Streaming
- mp4视频不支持边加载边播放(流媒体)的根本原因及解决方法
- 一种零成本提升视频服务器负载的方案
- [贝聊科技]首屏视频的优化过程(补充moov的研究)