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