Chrome absolute绝对定位display/visibility渲染bug

这篇文章发布于 2015年01月10日,星期六,02:38,归类于 CSS相关。 阅读 56187 次, 今日 2 次 22 条评论

 

一、Chrome虽好,可别贪杯哦~

一般我们对Chrome浏览器的评价是:Chrome好棒!Chrome好潮!Chrome就是多来A梦,要什么有什么!
好棒哦~

但是,再好的奶茶也会有过期的时候。很多次遇到,Chrome下的渲染表现是最糟糕的那个。比方说,在transform内部做CSS3 animation动画,Chrome会让文字一会儿粗一会儿细,甚至上下跳动,于是我们可以100%确认,这个页面是公的,会CSS3 animation的挑逗有反应。

嘛,毕竟只是细节上的不爽,睁一只眼闭一只眼也就过去了。但是,有些影响布局的bug可就没法视而不见了。你可能会惊讶:“纳尼!Chrome这么好的浏览器有bug, 会不会是你看错了?”

虽说Chrome是你见过的最单纯的姑娘,但是,真正相处久了,终究会发现,如果真的足够纯,就不叫奶茶了。

我这里给大家展示两个Chrome absolute绝对定位引发的渲染bug, 这些bug已经历经很多代(写本文时候使用Chrome版本是40)都没有修复了,跟我来~

follow me 跟我来~

二、Chrome下absolute绝对定位元素部分display属性值不渲染bug

此bug描述如下:

Chrome浏览器下,绝对定位元素,其display值在inline/inline-blockblock之间切换时候,是不重新渲染的。

百闻不如一见,您可以狠狠地点击这里:Chrome浏览器下绝对定位元素display渲染bug demo

我们进入demo,首先引入眼帘的是这个样子(张小姐抹白是为了节约至少60%图片尺寸大小,下同):
默认进入demo效果

此时,图片没有任何display设置,是默认的inline-block水平。要知道,元素absolute绝对定位,如果没有left/top等值,位置是不移动的(可参考我很多年前写的“CSS 相对/绝对(relative/absolute)定位系列(二)”一文),因此,紧随文字显示是没有任何问题的。

但是,当我们点击左边这个按钮,修改图片的display水平为block,尼玛图片居然还傻不拉几呆在后面,而且就Chrome浏览器是这样,IE8+以及Firefox之流都是萌萌哒换行显示:
Chrome浏览器下修改display为block后图片布局依然不动

FireFox下正确换行显示截图

//zxx: IE7也不会换行,但那是解析bug;而这里Chrome是不渲染bug~

如何修复此bug?
2年前的这个时候,我曾写过一篇文章:“利用重绘解决IE下JS交互产生的定位重叠等棘手bug”,可谓前端从业必读基础技能文章。
用一句话概述为就是:“遇到一些交互渲染bug时候,不妨触发浏览器的重绘,说不定问题即解决。”

这里Chrome不渲染bug修复中心思想也是一样的,就是触发重绘。但是,术业有专攻,代码有小受。上文中抛出来的visibility:inherit/visible切换方法在Chrome这里是没有效果滴!“我了个擦,这是要闹哪样?” 稍安勿躁,上帝关上了一扇门,那我们就换一个门出去。

这里隆重推出新时代webkit/blink内核渲染bug修复神器,业界俗称webkit届haslayout的东西:-webkit-transform: translateZ(0);

肉眼看上去,此申明对页面元素不会有什么影响;但是,好比老IE时代的zoom: 1。灭虫能力堪比敌敌畏!

我们回到demo,注意右侧蓝色按钮,对,就是那个含有“同时toggle translateZ”字样的按钮,此按钮是干嘛的呢?就是触发左侧按钮点击同时,给图片父级toggle切换translateZ(0)属性值,如下截图:
translateZ修复Chrome不渲染的问题

结果,图片正常渲染咯!——换行,跟随,换行,跟随,…… 好棒!

三、Chrome下absolute绝对定位元素具有overflow属性的块状子元素visibility hover不渲染bug

此bug具体描述如下:

Chrome浏览器下,绝对定位元素,同时visibility:hidden时候,如果子元素具有块状水平,同时设置了overflow:hidden; 则父元素hover时候,无法让子元素visibility:visible渲染生效!

百闻不如一见,您可以狠狠地点击这里:Chrome浏览器下绝对定位元素visibility渲染bug demo

我们先看HTML代码:

<div class="hover">
    Chrome罕见visibility渲染bug(<em>hover me</em>)
    <div class="abs_vh">
        <div id="bug" class="bug"><img src="mm1.jpg"></div>
    </div>
</div>

然后CSS代码:

.abs_vh {
    position: absolute; visibility: hidden;
}
.bug {
    overflow: hidden; /* 重要条件 */
}
.hover:hover .bug {
    visibility: visible; /* Chrome浏览器下,此声明无效 */
}

可以看到,HTML结构超级简单,CSS更是简单,总共就出现了4个CSS声明,但是,就是且必须这4个声明同时存在的时候,bug才会出现。

回到demo,我们hover demo页面文字,结果Chrome浏览器下,没有任何反应:
hover无变化

而爱意之流,火狐之流却风生水起:
IE11下效果正常 火狐Firefox浏览器下效果正常

由于一般人不会用到visibility的recover重置特性(类似还有cursor)(差不多3年前“您可能不知道的CSS元素隐藏‘失效’以其妙用”一文有介绍过visibility这个特性),因此,此bug几乎很难重现。

如何修复此bug?
我就不卖关子了,修复此bug的关键就是上面吹嘘过的神器,被誉为webkit界中的haslayout:-webkit-transform: translateZ(0);. 在需要visibility显示的元素添加这段CSS申明就可以了。

我们回到demo,有个光杆按钮,干嘛用的呢?给.bug这个元素toggle -webkit-transform: translateZ(0)这个声明。例如,我们点击下这个按钮,然后再去hover文字:
添加translateZ之后,Chrome问题修复

哦!!!小妹子图片显示出来了!好棒!

demo本着演示目的,在JS内联,实际上,要修复,CSS足矣,如下:
然后CSS代码:

.abs_vh {
    position: absolute; visibility: hidden;
}
.bug {
    overflow: hidden;
}
.hover:hover .bug {
    visibility: visible; 
    -webkit-transform: translateZ(0); /* 没错,靠的就是你!*/
}

由于上面两个bug都是来自Chrome,所以,神器使用了私有前缀,既不会影响其他OK浏览器,也似乎在大声表明:我就是hack,我就是补丁!

四、酒不醉人人自醉,结语写完就去睡

Chrome渲染的些bug自然不止本文这两个,主要是本文bug都由绝对定位absolute引发(可能高效渲染计算设计导致),然后都可以-webkit-transform: translateZ(0)修复,因此就放在一起讲了。

记得以前似乎见到过浮动随机渲染的bug;去年做iOS原型时候遇到过过场渲染的bug(夜太深,具体我记不清了),也是使用translateZ修复的。所以,如果大伙儿在折腾webkit内核页面时候,遇到奇怪渲染问题,都可以试试webkit界的haslayout, 渲染问题修复神器-webkit-transform: translateZ(0),说不定会有好运降临!

技术不止,进步不断,说不定下个版本问题就会被修复,到时,还希望广大同学提个醒,我好及时更新。

感谢阅读,有任何问题都欢迎交流!

(本篇完)

分享到:


发表评论(目前22 条评论)

  1. 说道:

    新版还存在的BUG,当前文章页面运行一下代码可以重现!

    var div = document.createElement(“div”);
    div.style.backgroundColor=”#f00″;
    div.style.position=”absolute”;
    div.style.width = “200px”;
    div.style.height = “200px”;
    div.style.left = “200px”;
    div.style.bottom = “50%”; //如果bottom属性换成top则没有此bug
    document.body.appendChild(div); //此时发现位置并非正确,如果body设置了relative也没有此bug

    document.body.style.transform=”translateZ(0)”; //神奇的解决了

  2. arrow说道:

    这几个bug都解决了
    我的版本是59

  3. 断崖上的风说道:

    今天也碰到chrome不重新渲染的bug了,不过不是display的,是关于 position 切换成 fixed 时,也出现了不重新渲染的情况。。。最后也是添加了一个 translateZ(0) 解决。。。。

  4. 老三快来说道:

    css3动画时,只要是x,y位移动画,例如: -webkit-transform: translateY(-500px); 会导致动画结束后大约有200ms-500ms不等的时间延迟,此时动画的元素上的鼠标事件全部不能响应,有没有同学遇到过同样问题,其它浏览器均正常!!!

    补充:在同样使用webkit内核的浏览器上如opera,safari均是正常的。。。

  5. 决明说道:

    我发现的chrome bug是在定位后背景png图片出现一个大白块,-webkit-transform: translateZ(0);无效,最后是用js让他display:none,然后sildeDown。。。。。

  6. 老斌说道:

    我也遇到了元素绝对定位显隐时的重叠问题。是在mac下的,刚开始用display block/hide显隐,但有问题,又换了visibility,貌似是解决了问题,过两天又发现当同级元素不够多,未排满一行的时候(这个不好描述)还是有问题,想到应该是需要让元素重绘或者内容区重新渲染,然后就无意间找到此文,bug就立马解决了,”业界良心”啊,哈哈,点赞

  7. bby说道:

    你好,最近遇到一个hover改变层级的问题,在chrome下hover会有闪烁,但是ff是正常的。
    我的代码:

    #f {
    width: 200px;
    height: 200px;
    background-color: red;
    position: absolute;
    z-index: 0;
    -webkit-transform: translateZ(0);
    }
    #f:hover {
    z-index: -2;
    -webkit-transform: translateZ(0);
    }
    #s {
    width: 200px;
    height: 200px;
    background-color: black;
    position: absolute;
    z-index: -1;
    -webkit-transform: translateZ(0);
    }
    #s:hover {
    z-index: 0;
    -webkit-transform: translateZ(0);
    }

    1
    2

  8. jfw10973说道:

    厉害!我也定位到是position影响 的页面无法重绘,但是没想到这么好的解决方案,举一反三,碰到类似的再也不慌了,关注你博客许久,非常感谢!

    已捐赠,加油!

  9. WingMeng说道:

    旭哥,慕课上的《CSS深入理解之absolute》怎么不更新了啊?期待好久了,求更新

  10. humphry说道:

    换个名称看看怎么样(Stone)

  11. Stone说道:

    路过打酱油的~~

    额 弱弱的问一下 这个博客提交评论的部分是通过邮件和名称去匹配用户的吗??邮件相当于密码??

  12. Humphry说道:

    那个,张鑫旭前辈,`position: absolute`会导致元素的display计算值是block,无论display原来的值是什么……个人觉得不算bug……

    • 张 鑫旭说道:

      @Humphry 你好,说的不是一个事~

      • Humphry说道:

        是这样的,对于position: absolute元素来说,无论其display为inline-block还是block,最终display的计算值为block(见http://www.w3.org/TR/CSS2/visuren.html#dis-pos-flo : Otherwise, if ‘position’ has the value ‘absolute’ or ‘fixed’, the box is absolutely positioned, the computed value of ‘float’ is ‘none’, and display is set according to the table below. The position of the box will be determined by the ‘top’, ‘right’, ‘bottom’ and ‘left’ properties and the box’s containing block.)。这样的话,在display从block到inline-block的切换中,并不会影响元素的布局模型,因此我认为依靠改变display属性来强制position: absolute元素重绘不太合适。

        • 张 鑫旭说道:

          @Humphry 你好,按照规范,元素绝对定位后,原本位置是不变的。我们说的不是一个事。

        • Humphry说道:

          元素绝对定位以后,display就当作block来计算了,改变其display属性为block,并没有计算值的变化,不重绘也没有问题。这是我的point……

  13. xiaowtz说道:

    测试了一下,scale(1),skew(0),rotate(0)都可以,这些都是触发了硬件加速么?

  14. Bob说道:

    Chrome快是快,不过牺牲的就是渲染质量,(相对于FF和IE)。以前遇到过CSS3动画的时候,Chrome会明显比其余两者慢。