移動端瀏覽器中的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…