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 的测试结论
- 使用 opaque/transparent 模式,只需 div 就可以遮挡住 Flash;
- 使用 window/direct/gpu 模式:
- IE 需要借助 iframe 才能遮挡 Flash
- Chrome 仅 div 即可遮挡 Flash
- Firefox 当使用 rgba 的半透明背景色浮层时,无法遮挡 Flash
- Windows Safari 即使 iframe 也无法遮挡 Flash
- 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 ,隐藏一个层通常有三种方式:
visibility:hidden;
display:none;
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:
- wmode 的五种取值下 Flash 隐藏再显示的均表现一致;
- IE gpu 模式,
visibility:hidden
的隐藏模式,会使视频回放1秒;
隐藏视频的结论:
visibility:hidden
和left:-1000px
的方式,IE6-10、Firefox、Chrome、Safari 浏览器中 Flash 的隐藏与显示都不影响其正常播放(若想隐藏 Flash 时暂停视频的播放,可以调用 Flash 相应的 js 方法实现);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>
元素。无需其他特殊处理。