移动端浏览器中的video元素是比较特别的,早期不管是在iOS仍是Android的浏览器中,它都位于页面的最顶层,没法被遮挡。后来,这个问题在iOS下获得了解决。可是对Android的大部分浏览器来讲,问题仍然存在。X5是腾讯基于Webkit开发的浏览器内核,应用于Android端的微信、QQ、QQ浏览器等应用。它提供了一种名叫「同层播放器」的特殊video元素以解决遮挡问题。css
只要给普通的video元素加上X5的自定义属性 x5-video-player-type ,就能够调用同层播放器。示例代码以下:html
body {
margin: 0;
background: #000;
}
.video {
width: 100%;
}
复制代码
<div class="player">
<video id="video" class="video" controls="controls" playsinline x5-video-player-type="h5">
<source src="video.mp4" />
</video>
</div>
复制代码
点击播放后,页面会瞬间拉伸(体验有点差),而后就进入了全屏状态,视频默认在中间位置:web
在全屏状态下,调整视频位置的通用作法是:把video元素的尺寸设成满屏,再经过 object-position 样式属性控制视频内容的位置。相关代码以下:浏览器
.fullscreen .video {
object-position: center top;
}
复制代码
var player = document.getElementById('video');
var isFullScreen;
// 进入全屏,设置状态
player.addEventListener('x5videoenterfullscreen', function() {
isFullScreen = true;
// 在body上添加样式类以控制全屏状态下的页面布局
document.body.classList.add('fullscreen');
}, false);
// 退出全屏时,清空状态
player.addEventListener('x5videoexitfullscreen', function() {
isFullScreen = false;
document.body.classList.remove('fullscreen');
player.style.width = player.style.height = '';
}, false);
// 同层播放器进入全屏状态会致使窗口resize,但退出全屏不会
window.addEventListener('resize', function() {
if (isFullScreen) {
// 设为屏幕尺寸
player.style.width = window.screen.width + 'px';
player.style.height = window.screen.height + 'px';
}
}, false);
复制代码
效果以下方左图所示,可见,此时视频距离顶部尚有一些距离。这个问题与 x5-video-player-fullscreen 属性有关。若是不声明这个属性,原标题栏的占位不会分配给页面,而是平均分红上下两块,分别位于窗口顶部和底部。所以,视频没法顶到最上方。微信
补充 x5-video-player-fullscreen 属性后,问题就解决了(上方右图):ide
<video id="video" class="video" controls="controls" playsinline x5-video-player-type="h5" x5-video-player-fullscreen="true">
<source src="video.mp4" />
</video>
复制代码
你们还能够发现,顶部有一层黑色渐变(上图不太明显,能够看下文的图)以及两个按钮。据官方文档所述,这些都是没法移除的。布局
实际业务中,页面多半不会只有一个视频这么简单,下面就开始添加其余页面元素(请行引入rem布局所需的脚本)。首先是在视频以前加上标题栏:ui
.header {
width: 100%;
height: 1.14rem;
line-height: 1.14rem;
background: #fff;
font-size: 0.36rem;
text-align: center;
color: #000;
}
复制代码
<header id="header" class="header">标题栏</header>
<div class="player">
<video id="video" class="video" controls="controls" playsinline x5-video-player-type="h5" x5-video-player-fullscreen="true">
<source src="video.mp4" />
</video>
</div>
复制代码
然而,点击播放进入全屏状态后,标题栏就消失了,其实它是被视频挡住了。既然同层播放器是能够被遮挡的,那能够试试绝对定位:spa
.fullscreen .header {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
}
复制代码
从下方左图可见,标题栏确实能够挡住视频了。code
此时视频内容被遮挡,因此要将其下移(上方右图):
.fullscreen .video {
object-position: center 1.14rem;
}
复制代码
接下来在视频以后添加其余页面元素,常规作法是限制视频区域高度,再进行后面的布局。但因为video元素自己在全屏状态下的宽高必须设成满屏,因此只能经过它的父元素(div.player)限制它的占位:
.player {
height: 4.22rem;
}
.fullscreen .player {
/* 全屏状态下重设高度,勿忘 */
height: 5.36rem; /* 4.22 + 1.14 */
}
.video {
width: 100%;
height: 100%;
}
.main {
box-sizing: border-box;
padding: 0.3rem;
height: 5rem;
background: #fff;
}
复制代码
<header id="header" class="header">...</header>
<div class="player">...</div>
<div id="main" class="main">这里是其余内容</div>
复制代码
而div.main自己是不须要作任何特殊处理的。然而,此时又出现了一个新问题:进入全屏状态后,视频控制栏不见了。缘由是,video元素的高度为屏幕高度,控制栏位于屏幕最底端,而div.player又限制了高度,致使video元素超出的区域被隐藏,天然就看不到控制栏了。幸亏,咱们还能够经过伪元素选择器修改控制栏的样式:
.fullscreen .player {
position: relative;
height: 5.36rem;
}
.fullscreen .video::-webkit-media-controls {
position: absolute;
bottom: 0;
}
复制代码
经过使控制栏相对于div.player定位,就可让它回到视频画面的底端了。最终效果以下图所示:
综上所述,在全屏状态下,video元素以前的元素须要作布局调整,而在其后的元素则不须要。
若是页面有滚动条,进入全屏状态后,是否还能够滚动呢?
笔者撰写本文初版(2017年中)的时候,全屏状态下的页面滚动会变成抖动,效果很是糟糕,而目前则是滚不了了。
因此,若是页面内容确实较多,只能使用元素内滚动了。
不得不说,原生控制栏的bug很是严重。
Bug 1:播放某些格式的视频时,进度条会出现错乱,即便退出全屏模式也仍是错乱。
Bug 2:控制栏的全屏按钮在某些状况(具体规律还没有查明)下无效。
Bug 3:整个控制栏在某些状况(具体规律还没有查明)下没法调出。
以上三个bug非必现。但为了躲开这些坑,建议屏蔽原生控制栏,自行开发一个控制栏。
上一节提到,原生控制栏的全屏按钮在某些状况下无效,这样一来就必须想其余方法去实现视频的全屏了,这里面最关键就是video元素的 x5-video-orientation 属性。它决定了同层播放器进入全屏状态后,当前窗口是横屏仍是竖屏(前文的全部描述中,都是竖屏的状况)。而且,它是能够动态设置的。
若是把 x5-video-orientation 设成横屏,再把页面上的其余元素隐藏掉,就跟全屏无异了。具体实现以下:
var isLandscape;
// 点击其余内容区域,进入全屏
var main = document.getElementById('main');
main.addEventListener('click', function() {
// 同层播放器进入全屏状态以后,才能让视频全屏
if (!isFullScreen) { return; }
// 修改 x5-video-orientation
player.setAttribute('x5-video-orientation', 'landscape');
isLandscape = true;
}, false);
// 检测窗口方向改变,修改布局
window.addEventListener('orientationchange', function() {
if (isLandscape) {
document.body.classList.add('landscape');
var width = window.screen.width;
var height = window.screen.height;
player.style.width = width + 'px';
player.style.height = height + 'px';
}
}, false);
复制代码
.landscape .header { display: none; }
.landscape .video { object-position: center center; }
.landscape .main { display: none; }
复制代码
要强调的是,从修改 x5-video-orientation 到窗口方向改变,须要必定的时间才能完成。所以,不要在修改以后立刻调整布局,而是要监听 window 的 orientationchange 事件,在事件回调中调整布局。此外,还要在退出全屏时,清空相关状态:
player.addEventListener('x5videoexitfullscreen', function() {
isFullScreen = false;
isLandscape = false;
document.body.classList.remove('fullscreen', 'landscape');
player.style.width = player.style.height = '';
}, false);
复制代码
最终效果以下(顶部的阴影和两个按钮仍然没法干掉):
本文初版写于2017年6月,当时刚接触同层播放器,因此文章内容只能算是一份试用报告。通过一年多的项目实践以后,有些旧问题找到了更好的解决方案,还发现并解决了一些新问题,而同层播放器自己也有一些变化,因而在2018年11月进行修订,发布第二版。
本文同时发布于做者我的博客: mrluo.life/article/det…