前言
keywords:transform
、fixed
、webkit
费点口舌讲一讲发现这个问题的来龙去脉,在移动端遇到了一个上传多个图片的需求,需要拖放改变顺序,还要有拖放动画,由于自己写的东西太渣,所以就直接使用了
基于原生javascript的插件sortable,但是在拖放的过程中发现他动态生成的跟随图片位置在页面滚动之后竟然向上偏移了,
然后我深究到它的源码当中,找到了这个方法:getBoundingClientRect()
,getBoundingClientRect用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。getBoundingClientRect是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)。该函数返回一个Object对象,该对象有6个属性:top,lef,right,bottom,width,height;这里的top、left和css中的理解很相似,width、height是元素自身的宽高,但是right,bottom和css中的理解有点不一样。right是指元素右边界距窗口最左边的距离,bottom是指元素下边界距窗口最上面的距离。
也就意味着用它得到的坐标给布局为fixed的元素使用再好不过了,但是这个时候我发现即使fixed布局top给定了360
,但是实际的top却只有318
,让我陷入了深思,第一次遇到fixed布局失效的问题。
正文
由于方法getBoundingClientRect()
获取的坐标就是相对于视窗的,此刻我们已经清楚了问题,不能让这个方法背锅,是fixed无效的问题,接下来我们继续查找问题,从google
中终于发现了一些蛛丝马迹,
下面我们来看一张图片:
看到这里可能大家并没有发现什么不妥,然而这张图片就是使用的fixed布局,但是在webkit内核浏览器下,由于他外层使用了transform,我这里写了硬件加速的方式,所以他的fixed布局失效了,
这里我列出它的代码结构:
html:
<div>
<img src="http://www.chengfeilong.com/img/loading.gif" data-src="/img/fixed/1.png" class="lazy">
</div>
css:
div{
transform:translateZ(0);
width:263px;
height:351px;
}
div>img{
position:fixed;
top:0;
left:0;
}
我们可以理解为:在父级有使用transform的情况下(无论哪一个父级),内部如果出现fixed布局的话,在webkit内核浏览器下这个元素的表现形式 更像是一个使用absolute的元素,它会因为父级含有transform元素的上下文作用,使得自身的fixed失效,出现了跟随的效果。
解决方法
我对相关内容进行了大量的查阅,解决方法有,但是众说纷纭。
所以我采用了一个最笨的办法,既然父子级最出现这种情况,那我就不让它们形成这种关系。
我让sortable
插件生成的ghost
图片生成在body下而不是在当前dom下,以此出发点解决问题,在使用了插件的fallbackOnBody
属性后解决了自己在实际中遇到的问题。
最后提供一些我查阅到的相关信息和解决办法:
知乎
张鑫旭
stackoverflow
补充
更新于2016/04/16
好吧,transform
的坑还是真的多,最近遇到了有人反馈移动端访问我的博客时想要留言,结果访问方式登陆窗被正文内容给遮盖住了。
其实这个问题我之前测试过的,在chrome模拟器下并没有这种的问题,然后仔细研究了多说生成的登陆窗口,在body层下生成了一个z-index
为9999
的fixed布局元素。然而我的文章内容跟该元素属于并列层级,而且并非fixed布局,z-index
不到1000,讲道理不可能会发生这样的事情,然而真相却不是这样,
自己就一层层看自己的博客布局,结果扒到了设置transform
这层,我心里不由得一慌,因为我设置了
div{
-webkit-transform: translate3d(0,0,1px);
}
使我的页面滚动启动硬件加速,使刚滑动的时候不会发生卡顿的现象,果然当我取消了该层级的transform
属性时。
fixed登陆窗口果然不被遮盖了!!!
原来并非父子级关系他们之间有相互影响,并列层级之间使用transform和fixed的时候,z-index
并没有什么(luan)用,
在查阅了 w3c 后可以简单的说,使用transform
的时候会改变页面的层叠关系,最受影响的就是z-index
这个属性,即使fixed布局
设置了及其高的z-index
值,也是会被transform
的层叠关系影响而被遮盖!