控制页面元素的显隐性,大家用的比较多的还是display属性,通过none和block或者其他值的切换,来完成显示与隐藏的功能。但其实visibility属性,也是控制显隐性的,大家应该也都知道,只是平时用到的可能比较少,一个是因为它只是可见性的切换,还一个原因可能是这个属性比较长(哈哈)。但是我要说的,在某些场合下,visibility属性却要比display更加有用,并且性能更优。
可识别性
首先我们看看可识别性,visibility:hidden的元素,实际上只是看不见而已,它的位置,空间大小依然存在,说白了,浏览器里会显示一块空白地方,这个也是通常大家不用它控制显隐的原因——没有真正的让元素消失在视野里。而display就是彻底的消失,浏览器看不见,渲染树里也不会有它的位置。然而就是这一点区别,却在一些场合下能发挥很大的作用。
首先,就是浏览器的性能。
正如上面所说visibility属性只是控制元素的可见性,不会使元素从渲染树中消失或者改变整体布局,元素实际上已经存在于整个渲染树中(js可获取宽高),因此它的显隐不会触发浏览器的重排,仅仅是重绘。而display会让元素从渲染树中消失,是真正的不存在(用js是无法获取到高度宽度),因此如果显示的时候,会触发浏览器的重排,重新绘制整个渲染树。而重排是影响性能的主要问题,所以只要有可能,都要减少重排的出现。如下图,是火狐控制台给出的,第一个操作是display,第二个操作是visibility,可见,第一次操作触发了两次“布局”,即浏览器重新排版了渲染树,而第二次没有,大家可以自行测试。
其次,上面也提到了,visibility元素可以识别,所以可以用js获取宽高等等一系列正常元素可以获得属性值,而display是不行的,如果涉及到此种操作,visibility显然比display更合适。
布局应用
基于visibility的可识别性,一些布局上的操作也是优于display的。
首先,页面加载。通常我们会设置一个加载图片来告诉用户页面正在加载,然后通过回调函数,隐藏加载图片,显示实际页面,如果此时用display,在图片比较少的情况下,问题不大。但是正如上面所述的,display会触发重排,所以页面会发生抖动,等于一些元素重新被撑开,图片重新加载显示,尤其图片多的时候,问题更显著;而此时使用visibility,是不会有这个问题,页面都已经加载好了,只是显示出来而已,不会触发重排,也不会让页面抖动。
其次,如果大家使用过echarts,就会知道,echarts的canvas画布显示是基于其容器大小的,如果display控制显隐,元素相当于从0扩展到正常大小,虽然时间可以忽略,但对于echarts是致命的,它会挤成一团,必须重新调用resize方法才能恢复,页面不仅晃动,而且会有卡顿,这种问题通常出现在切换显示echarts的时候;而使用visibility,将相应的图层利用绝对定位叠在一起,这样切换,完全不会有任何问题,而且visibility在hidden状态时,是不会遮盖其他元素的,对于echarts或者有类似需求的布局,完全可以使用visibility来代替display,并且兼容性无忧。
第三,针对与鼠标移入显示菜单的功能布局,display可以胜任,但是它总会立刻出现,不能控制延时。原因就是transition属性不支持display,究其原因,我总结的就是display:none的不能识别,它不存在于渲染树中,无法获取对它的相应控制;而visibility属性是被支持的,因此利用transition,visibility,可以实现元素的延时显示与立即消失,如果你的这种下拉菜单设计是在列表中,visibility会是最好的选择。因为延时显示,不会因为鼠标误移入而突然显示;立刻消失,又会让它在鼠标移出时,不至于遮挡住下面的内容。
所以可见,其实visibility属性在一些特定场景下实用性是强于display,甚至可以替代display,当然基于visibility的应用不仅限于以上三种场景,大量的应用,可以在实践中慢慢找寻,日后再遇到显隐性问题,visibility和display二者应该同等予以考虑了。