div 浮层遮盖 flash 问题再研究

Posted by 任平生 on April 30, 2014

div 浮层遮挡 Flash 的研究汗牛充栋,随便 Google 一下都能找到浩如烟海的资料,最简单的解决方案就是使用 wmode="opaque" 或者 wmode="transparent",如此的简单而又一劳永逸。

没有特殊需求的到这里就可以止步了,但是 wmode="opaque" 并不适合所有网站,比如视频网站,视频网站对 Flash 的表现性能有着极致的追求,让我们更倾向选择使用 wmode="window",现在有了更好的 wmode="driect" 模式。而在 window/driect 的模式下,普通的 div 浮层很难完美地实现遮挡 Flash 的需求。

Wmode 的五种取值

首先,我们了解一下 wmode 五种不同取值的含义

Window模式

默认情况下的显示模式,在这种模式下 flash player 有自己的窗口句柄,这就意味着 flash 影片是存在于 Windows 中的一个显示实例,并且是在浏览器核心显示窗口之上的,所以 flash 只是貌似显示在浏览器中,但这也是 flash 最快最有效率的渲染模式。由于他是独立于浏览器的HTML渲染表面,这就导致默认显示方式下flash总是会遮住位置与他重合的所有 HTML 层。

Opaque模式

这是一种无窗口模式,在这种情况下flash player没有自己的窗口句柄,这就需要浏览器需要告诉flash player在浏览器的渲染表面绘制的时间和位置。这时flash影片就不会在高于浏览器HTML渲染表面而是与其他元素一样在同一个页面上,因此你就可以使用 z-index 值来控制 HTML 元素是遮盖 flash 或者被遮盖。

Transparent模式

透明模式,在这种模式下 flash player 会将 stage 的背景色 alpha 值降为 0 并且只会绘制 stage 上真实可见的对象,同样你也可以使用 z-index 来控制 flash 影片的层级值,但是与 Opaque 模式不同的是这样做会降低 flash 影片的回放效果,而且在 9.0.115 之前的 flash player 版本设置 wmode="opaque""transparent" 会导致全屏模式失效。

Direct模式

直接渲染模式,在该模式下,flash player 可以通过硬件直接对画面进行合成,并呈现在屏幕上。使用这种模式能够得到比 window 模式更好的渲染效果,特别是在视频播放方面,如果页面的 flash 需要使用了 stagevideo 或者 stage3D,那么必须使用这种模式。它有比 window 模式更好的渲染,但也有 window 模式下的所有缺点。

GPU模式

在一些网络电视和移动设备上可以启用额外的硬件加速,与其他 wmode 值模式相比,显示序列的像素保真度无法保证,其他方面跟 direct 模式相似。

各家视频网站的 wmode 取值

Youku Tudou Tencent Video iQiyi Sohu TV Letv Sina Video Youtube Vimeo Hulu Flickr Video
N/A window/opaque direct window opaque opaque transparent N/A opaque N/A opaque

N/A 表示没有设置 wmode 值,此时 Flash 默认使用 window 的取值。 土豆在 XP 下的 IE 和 Chrome 使用了 opaque,其他情况下是 window。

有40.9%的视频网站采用了 window 的模式;还有 40.9% 的选择使用 opaque。 window 和 opaque 平分秋色,这样看来 opaque 也应该是一个不错的选择。(不知是这些网站的前端偷懒,还是性能上真的OK。这个稍后需要做一个性能测试后再分享相关数据)

div 遮盖 Flash 的测试结果

接下来我们来测试不同的 div 浮层遮挡不同 wmode 取值的 flash 的效果,下边是测试结果一览表:

wmode=window Windows Mac
IE6-IE10 Chrome Firefox Safari Safari Chrome Firefox
div
div + iframe
div(rgba)
div(rgba) + iframe
wmode=direct Windows Mac
IE6-IE10 Chrome Firefox Safari Safari Chrome Firefox
div
div + iframe
div(rgba)
div(rgba) + iframe
wmode=gpu Windows Mac
IE6-IE10 Chrome Firefox Safari Safari Chrome Firefox
div
div + iframe
div(rgba)
div(rgba) + iframe
wmode=opaque Windows Mac
IE6-IE10 Chrome Firefox Safari Safari Chrome Firefox
div
div + iframe
div(rgba)
div(rgba) + iframe
wmode=transparent Windows Mac
IE6-IE10 Chrome Firefox Safari Safari Chrome Firefox
div
div + iframe
div(rgba)
div(rgba) + iframe

注:div(rgba) 指定义浮层背景半透明色的情况,CSS 代码: background-color:rgba(255,255,255,0.6)

div 遮盖 Flash 的测试结论

  1. 使用 opaque/transparent 模式,只需 div 就可以遮挡住 Flash;
  2. 使用 window/direct/gpu 模式:
    1. IE 需要借助 iframe 才能遮挡 Flash
    2. Chrome 仅 div 即可遮挡 Flash
    3. Firefox 当使用 rgba 的半透明背景色浮层时,无法遮挡 Flash
    4. Windows Safari 即使 iframe 也无法遮挡 Flash
    5. Mac 系统下 wmode 取任何值, div 元素都能轻松遮挡 Flash 元素

特例1: Windows 版的 Firefox

只有具有背景色(background-color:#fff)的元素才能遮挡 Flash,透明背景(background:transparent),或者背景颜色为半透明(background-color:rgba(255,255,255,0.5)),或者使用半透明图片(background:url(alpha.png))做背景的元素都无法遮挡 Flash

特例2: Windows 版的 Safari

上述 2.4 的结论有点让人沮丧,虽然 Windows 版 Safari 的份额处于异常边缘的位置,不过遇到这个问题还是解决,我们的解决方案是,当出现需要遮盖 Falsh 的浮层时候,暂时隐藏 Flash ,隐藏一个层通常有三种方式:

  1. visibility:hidden;
  2. display:none;
  3. positiona:relative;left:-1000px;

这里我们需要的隐藏应当达到如下效果:视频暂时不可见,浮层关闭后,Flash 视频应当继续播放。

以下是在 Windows 版各个浏览器中的测试结果

IE6-IE10 Chrome Firefox Safari
visibility:hidden A A A A
display:none A B B B
left:-1000px A A A A

注1:

  • A: 视频隐藏,继续后台播放,切换回来后可继续正常播放
  • B: 视频隐藏,停止播放,切换回来后从头重新开始播放

注2: 

  1. wmode 的五种取值下 Flash 隐藏再显示的均表现一致;
  2. IE gpu 模式,visibility:hidden 的隐藏模式,会使视频回放1秒;

隐藏视频的结论:

  1. visibility:hiddenleft:-1000px 的方式,IE6-10、Firefox、Chrome、Safari 浏览器中 Flash 的隐藏与显示都不影响其正常播放(若想隐藏 Flash 时暂停视频的播放,可以调用 Flash 相应的 js 方法实现);
  2. display:none ,会导致视频在 Chrome、Firefox、Safari 中视频重新加载,从头开始播放;

这里建议使用 visibility:hidden 的方法来隐藏视频,兼容性和对页面重绘的影响都最小。

div 遮挡 HTML5 视频研究

说完 Flash 了,我们顺道研究一下 div 浮层遮挡 HTML5 Video 是否会有问题。经测试,结果如下表:

HTML5 Video Windows Mac iOS Android
IE9-IE10 Chrome Firefox Safari Chrome Firefox Safari Chrome 原生 Chrome UC
div
div + iframe
div(rgba)
div(rgba) + iframe

注: iPhone 上当视频播放时会自动切换为全屏,此时没有任何页面元素可以遮挡它。当视频处于非全屏的暂停(或未开始播放)状态时, div 浮层可以遮挡 <video> 元素。iPad 上无此问题。

HTML5 Video 的得天独厚的优势 —— 无插件的视频播放,使其跟页面其他元素处于一种平等的层级关系上,div 浮层轻轻松松即可实现遮挡 <video> 内容。

div 浮层遮挡 Flash 的最终结论

对于 Flash Windows 系统下: 如果可以使用 wmode="opaque" 或者 wmode="transparent" , div 浮层遮挡 Flash, 只需设置好 div 浮层的 z-index 即可。

如果必须使用 wmode="window" 或者 wmode="driect" ,兼容各个浏览器的 div 浮层遮挡 Flash 的方案是使用 div + iframe 方式,而如果实现半透明的浮层效果(包括:背景色使用rgba,背景图带有透明的 png、gif 等),则要对 Firefox 进行特殊处理,单独定义 Firefox 使用纯色的背景。

/* Fierfox hack 参考 */
@-moz-document url-prefix(){
	.div_layer { 
		background-color: #fff;
		border-radius: 0; /* 遮挡Flash的浮层若设置圆角,在 Firefox 上会出现缺角的bug,需重置为0 */
	}
}

若还需要兼容 Windows 版的 Safari,则需要在遮挡 Flash 的浮层出现时,隐藏掉 Flash,隐藏 Flash 的方法推荐使用 visibility:hidden

Mac 系统下: 无需担心 div 浮层的遮挡关系, 只需设置好 z-index 即可。

对于 HTML5 <video> 元素 无论 Windows、Mac、iOS 还是 Android,普通的 div 元素都能轻松遮挡 <video> 元素。无需其他特殊处理。