移动端浏览器中的video元素是比较特别的,早期无论是在iOS还是Android的浏览器中,它都位于页面的最顶层,无法被遮挡。后来,这个问题在iOS下得到了解决。但是对Android的大部分浏览器来说,问题仍然存在。X5是腾讯基于Webkit开发的浏览器内核,应用于Android端的微信、QQ、QQ浏览器等应用。它提供了一种名叫「同层播放器」的特殊video元素以解决遮挡问题。
简单使用
只要给普通的video元素加上X5的自定义属性 x5-video-player-type ,就可以调用同层播放器。示例代码如下:
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>
点击播放后,页面会瞬间拉伸(体验有点差),然后就进入了全屏状态,视频默认在中间位置:
调整位置
在全屏状态下,调整视频位置的通用做法是:把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 属性后,问题就解决了(上方右图):
<video id="video" class="video" controls="controls" playsinline x5-video-player-type="h5" x5-video-player-fullscreen="true">
<source src="video.mp4" />
</video>
大家还可以发现,顶部有一层黑色渐变(上图不太明显,可以看下文的图)以及两个按钮。据官方文档所述,这些都是无法移除的。
全屏状态下的布局
实际业务中,页面多半不会只有一个视频这么简单,下面就开始添加其他页面元素(请行引入rem布局所需的脚本)。首先是在视频之前加上标题栏:
.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>
然而,点击播放进入全屏状态后,标题栏就消失了,其实它是被视频挡住了。既然同层播放器是可以被遮挡的,那可以试试绝对定位:
.fullscreen .header {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
}
从下方左图可见,标题栏确实可以挡住视频了。
此时视频内容被遮挡,所以要将其下移(上方右图):
.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月进行修订,发布第二版。
评论 (12条)