移動端瀏覽器中的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月進行修訂,釋出第二版。
本文同時釋出於作者個人部落格: mrluo.life/article/det…