webkit 里会出现突然闪一下的问题

问题

有用户反馈在 chrome 下出现屏幕会闪,但不是每次都能复现。

解决办法

.no-flick{-webkit-backface-visibility: hidden; /*但不能用于 sprite 雪碧图*/}
/* 或 */
.no-flick{-webkit-transform:translate3d(0,0,0);}

过程

昨天晚上 maomao ,晓刚我提起,会否是我们的「浮层」导致。逻辑是因为

  • 「浮层」 的 style 加了 opacity 。
  • 页面还没 load 完毕就把 mask 给加到 body 第一个元素了,这时没有加 display:none 。

而后我在「浮层」的蒙板 mask 把 background:white 改成 Red 。
很遗憾是没有出现红色。

所以,确定不是「浮层」的 mask 导致的问题。

在调试的时候感到幸运的是:
发现「闪」这个问题,都是闪在页面头部,经过精简后发现是在

<a><i><i></a>

标签里。

晓亮提到会否是 Transform 引起的。
试后,去除 transform 果然管用。
但是我们仍然没有知道解决办法,以及为何这样。

在百度上搜索类似 css 3 transform bug ,无果。 别灰心,在 stackoverflow 上 看看。 query: "transform flick bug webkit"

果然有料。
http://stackoverflow.com/questions/3461441/prevent-flicker-on-webkit-transition-of-webkit-transform

-webkit-backface-visibility: hidden; /*但不能用于 sprite 雪碧图*/
/* 或 */
-webkit-transform:translate3d(0,0,0);

来解决「闪」的问题。

如果用 translate3d 这么解决,心里想这不是用 3d 另一个问题解决现在 css3 3d 的一个问题吗。 顺着往下找了下资料。

果然如此, translate3d 有问题:

However, the body {-webkit-transform} approach causes all elements on the page to effectively be rendered in 3D. This isn't the worst thing, but it slightly changes the rendering of text and other CSS-styled elements.

It may be an effect you want. It may be useful if you're doing a lot of transform on your page. Otherwise, -webkit-backface-visibility:hidden on the element your transforming is the least invasive option.

所以,从目前来看 -webkit-backface-visibility: hidden; 是最优解。

弄清源头

关于这个 css3 属性拿来作什么用的。可以查阅
w3c 资料 http://www.w3.org/TR/css3-3d-transforms/#backface-visibility-property

The ‘ backface-visibility ’ property determines whether or not the "back" side of a transformed element is visible when facing the viewer. With an identity transform, the front side of an element faces the viewer. Applying a rotation about Y of 180 degrees (for instance) would cause the back side of the element to face the viewer. This property is useful when you place two elements back-to-back, as you would to create a playing card. Without this property, the front and back elements could switch places at times during an animation to flip the card. Another example is creating a box out of 6 elements, but where you want to see the inside faces of the box. This is useful when creating the backdrop for a 3 dimensional stage.

用这个属性做翻卡片的小游戏比较合适 :) 。
测试运行以下代码,就能理解为什么会在 transform 时会闪:

<!DOCTYPE HTML>
<html>
<head>
<style type="text/css"> 
#div1 {
width:120px;
height:100px;
background-color:yellow;
border:1px solid black;
-moz-transform:rotateY(25deg); /* Firefox */
-webkit-transform:rotateY(25deg); /* Safari and Chrome */
transform:rotateY(25deg);
}
</style>
<script type="text/javascript">
function rotate(value) {
  document.getElementById('div1').style.webkitTransform = "rotateY(" + value + "deg)";
  document.getElementById('div1').style.MozTransform = "rotateY(" + value + "deg)";
  document.getElementById('div1').style.transform = "rotateY(" + value + "deg)";
  document.getElementById('span1').innerHTML = value + "deg"
}
function checkBackface() {
  if (document.getElementById("bf").checked == true) {
    document.getElementById('div1').style.webkitBackfaceVisibility = "hidden"
  } else {
    document.getElementById('div1').style.webkitBackfaceVisibility = "visible"
  }
}
</script>
</head>
<body>
<div id="div1">HELLO</div>
<p>Rotate the yellow div element, with and without checking the backface-visibility checkbox:</p>
<p>Hide the backside:<input type="checkbox" onchange="checkBackface()" id="bf" /></p>
Rotate:<br />
<input type="range" min="-360" max="360" value="25" onchange="rotate(this.value)" /><br />
-webkit-transform: rotateY(<span id="span1">7deg</span>);
</body>
</html>

transform 是 3D 变换,而 backface-visibility:hidden ,则是在背面隐藏,实际上就变成了 2D 。
而把 translate3d 变换关闭也可以,但性能不好。

结论

在用

  • position:absulote+zindex!=0
  • 用 transform 会偶尔出现页面会闪的现象

确实是 chrome 的一个 bug 。
chromium 里没有发现有人提 bug ,所以我检索了一下 webkit.org 的 bugtrace ,看到

无疑,这个问题后续 webkit 一定会 fix 。
另,-webkit-backface-visibility: hidden; 是最优解。

-- EOF --

Comments