chrome对visibility继承的渲染bug一例

15 八月, 2011 (16:44) | Web技术及应用 | By: Cutsin

在做#skyLand框架时,发现chrome的一个渲染bug,草草解决了。然后被同事再度揪出,囧……
幸好它真的是chrome的bug,遂总结纪念:

w3对visibility:hidden的解释:

  1. visibility可继承;
  2. 属性值hidden使元素不可见(全透明,不渲染),但仍然影响布局。另外,该元素的后代如果设置了属性值visible,它们会是可见的。

由此我们应该认为下面例子中,不管点哪个按钮,#boy#girl都应是同时可见的:
<style>
.parents {visibility:hidden;z-index:1;position:relative}
.parents div {visibility:visible;position:relative}
.noDis {display:none!important}
.noVis {visibility:hidden!important}
</style>
<script>
function $(o){return document.getElementById(o)}
function showKids(s){
$('boy').className=''
if(s)
$('girl').className=''
else
setTimeout(function(){$('girl').className=''},0)
}
</script>
<button onclick="showKids(1)">show kids</button><button onclick="showKids()">show kids later</button>
<div class="parents">
<div id="boy" class="noDis">Go! Daddy~ ^^</div>
<div id="girl" class="noVis">Hi! Mommy~ ^^</div>
</div>

但在chrome中,点show kids later后,#boy不见了,其他浏览器正常。
现象分析:

  1. 初始时,父元素设invisble,子元素设visible且display:none,动态移除display:none时,webkit未能更新
  2. #parents中,只要初始时存在任何visibility:visible的元素,其他元素(如#boy)的渲染就能正常
  3. 如果渲染失败,用鼠标反选一下也能正常显示

然后,

  1. 点上例的show kids later,用setTimeout将#girl和#boy“分两步”处理,渲染失败
  2. 点上例的show kids,同时处理#girl和#boy,渲染正常

猜到的可能原因是:chrome(当前版本13.0.782.112)对渲染做了某些优化(比如执行缓存),但存在bug,同样webkit内核的safari正常。

总结该bug的触发条件:

  1. 父元素visibility:hidden,position非static,z-index非auto
  2. 初始时,父元素内部没有任何计算值为visibility:visible的元素
  3. 内部元素(且称为bad)visibility:visible,position非static
  4. 初始时,bad的display为none

然后,bad改变display为非none时,无法渲染。

原因清楚后,最终的解决方法也很简单,增加默认visible的元素即可:
.parent:after {visibility:visible;content:''}

错误示例页:http://moonless.net/demo/30

Related posts:

  1. “解耦”的字符分隔tag

Write a comment