您的位置:首页 > Web前端 > CSS

记一次CSS弹出动画的Bug

2016-03-29 16:13 435 查看
在写 jQuery WeUI 的一个picker的弹出动画的时候,我是通过CSS动画实现的。

CSS代码如下:

.weui-picker-modal {
width: 100%;
position: absolute;
z-index: 100;
bottom: 0;
text-align: center;
border-radius: 0;
opacity: 0.6;

color: @color-text;
transition-duration: .3s;
height: 13rem;
background: #EFEFF4;

transform: translate3d(0, 100%, 0);
transition-property: transform, opacity;

&.weui-picker-modal-visible {
opacity: 1;
transform: translate3d(0,0,0);
}
}


JS代码如下:

$.openPicker = function(tpl) {

var container = $("<div class='weui-picker-container'></div>").appendTo(document.body);
container.show();

container.addClass("weui-picker-container-visible");

//关于布局的问题,如果直接放在body上,则做动画的时候会撑开body高度而导致滚动条变化。
var dialog = $(tpl).appendTo(container); //

dialog.show();     //注意这一行奇怪的代码

dialog.addClass("weui-picker-modal-visible");

return dialog;
}


其实原理很简单,就是创建DOM的时候,通过 translate 把弹窗Y轴向下平移 100%,于是就看不到了,然后显示的时候再设置 Y 轴平移为0,就可以看到一个CSS动画的弹出效果。

但是测试发现在 iOS版的微信中就无法出现弹出动画,安卓以及PC上都没问题。

按道理讲是应该有动画的,因为我是先创建了DOM,并插入到页面,然后才添加了
weui-picker-modal-visible
类做动画。但是事实却是iOS上第一次没有弹出动画,那么也就意味着其实在IOS上,创建DOM和添加
weui-picker-modal-visible
其实是合并成了一步,才会出现打开的时候没有弹出动画。

注意这一行奇怪的代码
dialog.show()
,其实这一行代码就是想确保在添加类之前让DOM已经创建完毕。然后突然想到之前我有研究过JS性能优化相关的内容,其中有一条大意就是“如果连续对DOM进行多次操作,浏览器可能会调整这些操作的顺序以提升性能”,其实就是说浏览器会把DOM的修改操作尽量提前到被插入文档流之前进行,因为插入文档流之前进行修改就不需要进行渲染,所以这里其实如下三行代码在IOS中其实被提前到了DOM插入操作前:

var dialog = $(tpl).appendTo(container); //
dialog.show();     //注意这一行奇怪的代码
dialog.addClass("weui-picker-modal-visible");


本来是先把DOM插入文档流,然后进行DOM操作,优化后大致相当于变成了这样:

var dialog = $(tpl);
dialog.show();     //注意这一行奇怪的代码
dialog.addClass("weui-picker-modal-visible");

dialog.appendTo(container); //把上述三行代码先执行,然后再插入文档流,以提升性能。


那么很明显,这样做是无法出现动画的。而如何避免出现这种情况呢,之前的博客也提到了,就是在插入文档流之后,执行一次读取CSS属性操作,于是浏览器不得不立刻执行插入操作才能计算出CSS的属性值:

$.openPicker = function(tpl) {

var container = $("<div class='weui-picker-container'></div>").appendTo(document.body);
container.show();

container.addClass("weui-picker-container-visible");

//关于布局的问题,如果直接放在body上,则做动画的时候会撑开body高度而导致滚动条变化。
var dialog = $(tpl).appendTo(container);

dialog.width(); //改动这一行代码,通过取一次CSS值,强制浏览器不能把上下两行代码合并执行,因为合并之后会导致无法出现动画。

dialog.addClass("weui-picker-modal-visible");

return dialog;
}


只需要改动一行代码即可解决这个bug。之前认为进行一次
show
操作就可以保证已经实际插入文档流了,这种想法是错的,只有进行一次CSS属性的读取才能百分百保证。

可能有人要问为什么只有iOS上有这个问题,那估计是因为iOS更加重视这种UI上的性能优化,所以尽量进行DOM操作的合并。

所以如果大家以后自己写CSS动画,创建一个DOM之后立刻加一个类进行动画,也有可能会碰到这种bug,那么只需要在添加动画类之前随意读取一个CSS属性即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息