IE filter & z-index bug
对最近遇到的2个问题的一点总结。
1.IE filter & z-index
重构后的首页即将上线,测试提出fix导航条扩展菜单在ie789滚动后一段无法显示的问题。
疑云重重:
这个问题一开始一度以为是fix本身的bug,因为之前顶部的滚动切换是写成了500固定值,并没留意到bug触发真正机理,加之fix在ie低版本确实存在一些问题,但是base库中tb函数本身并不存在问题。
之前的扩展菜单都是用js动态去算位置,个人觉得这样滥用js是极为不好的,使用css来制作,扩展菜单是作为主菜单的子元素一部分,给予扩展菜单相对主菜单绝对定位即可,css可以很好的实现它,并且代码也更加优美。
初步猜测:
昨个自己优化复测时发现在平板竖屏下,由于slider高度变得较小,如果再滚500再触发感觉就体验较差(本来想把关联设定成可自定义的元素,不过为了避免近期改动较多暂时搁置)。
由于改了这个数值后,当再次检测这个Bug时,可以清晰发现就是在触发scroll切换导航条class后发生了这个bug。
如果研究过ie filter的机制就马上能想到原因了,不了解的可以拿透明边框(ts)在ie6下测试,能更好的理解filter的镂空原理。
故而想到了,因为是后来触发了filter,而触发filter的时候,此时display:none的扩展菜单被直接镂空处理了,而箭头是用伪元素制成的,可以看出来伪元素不受影响?
感谢斌哥一起帮忙耐心测试。到这里,我以为:ie filter处理,针对自身元素,包含子元素,但不包括伪元素。当有hide/show切换的子元素时,会造成该元素镂空。
豁然开朗:
正好周末回家,准备再次梳理一下,打开test再次测试,却发现远不是那么简单。
例如我们写一个父元素,父元素为半透明,有应用filter,里面装个子元素,子元素通过位移离开父元素的元素占位区间。
测试结果1:子元素默认可见,通过margin位移,此时,尽管子元素并没有display:none,它依旧无法显示,包括伪元素。
测试结果2:子元素默认可见,通过绝对定位位移,表现正常,包括伪元素。
测试结果3:子元素默认隐藏,通过绝对定位位移,表现正常,包括伪元素。
到这里为止我们可以确定,其实ie的filter只是自身平面上元素,而绝对定位的子元素并不受影响,也就是说和display:none没有半毛钱关系。
对比线上案例,线上案例就是绝对定位呀,为什么却不显示呢,并且箭头,伪元素是显示的。
打开IE11审查工具测试可知,js操作正常,扩展菜单也确确实实存在,取消父级filter确实就能显示了,但这和本地的测试并不一致。
冥思苦想片刻,这并不是上面推理出来的结论错误。
注意到父级是有设置z-index的,惊奇的发现,这个现象和父级与子级的z-index并没有半毛钱关系,不论数学逻辑关系如何,关键是父级有设置z-index时,则回到测试结果1的现象。
最后查一下stackoverflow和google,终其原因还是filter与z-index的渲染绘制冲突原因。
虽然其他童鞋给出了其他可以参考的解决方案,但是我认为最佳的考虑方案还是直接上png半透明背景图。
http://tagsoup.github.io/blog/2011/12/29/ms-filters-make-me-hate-life-memoirs-of-a-fe-ender/
http://www.telerik.com/forums/menu-z-index-issue-ie-8-and-9
2.display:none 与 visibility:hidden
还是上面的菜单,由于考虑兼容的问题,必须js动态给予扩展菜单宽度。
由于本身扩展菜单宽度实际上只能是等同于主菜单,并且由于每个li的宽度并不一致,我们通过css设置禁止折行后,需要逐一获取每个li单元的宽度累加。
但是如果菜单默认是display:none的话,则所有的css属性为空,转换为数值后则为0,则无法正常渲染,除非这个行为发生在show的回调函数中,但是如果写在show的回调中,菜单的内容会逐一蹦出来,这也不是我们要的效果。
故,部分类似情况下,应用hidden代替none。