css重绘和回流的例子
时间:2023-03-30 14:32:35
CSS
最近做了一个导航栏动画。当鼠标悬停时,会有一条可移动的下划线。html结构大致如下BBBCCCDDDD
slider-underline使用过渡样式:.slider-underline{position:absolute;边框宽度:1px0;边框样式:实心;边框颜色:#444;高度:0px;底部:12px;宽度:26px;贝塞尔曲线(0.16、0.71、0.46、1.43);-moz-transition:left0.2scubic-bezier(0.16,0.71,0.46,1.43);-o-transition:left0.2scubic-bezier(0.16,0.71,0.46,1.43);过渡:升eft0.2scubic-bezier(0.16,0.71,0.46,1.43);}生成页面时,需要根据不同的section初始化slider-underline的位置varunderline_width=$('.slider-underline').width();varactive_position=$('.nav-sliderbar.active').length?$('.nav-sliderbar.active').width()/2+$('.nav-sliderbar.active').position().left-underline_width/2:-underline_width;//上面两句是计算出导航栏滑块的初始位置,就在激活板对应位置的正下方。$('.slider-underline').css('left',active_position+'px');由于slider-underline默认是有transition的,当页面刷新初始化其左侧位置时会触发动画效果。这个体验不是很好。希望在初始化的时候不要触发这个动画,所以考虑把动画效果做成类:.underline-bezier{-webkit-transition:left0.2scubic-bezier(0.16,0.71,0.46,1.43);-moz-transition:left0.2scubic-bezier(0.16,0.71,0.46,1.43);-o-transition:left0.2scubic-bezier(0.16,0.71,0.46,1.43);transition:left0.2scubic-bezier(0.16,0.71,0.46,1.43);}在js下面添加:$('.slider-underline').css('left',active_position+'px');$('.slider-underline').addClass('underline-bezier');不过这里有个问题,这样做之后页面效果并没有变化。按理说修改left会导致页面重绘重排,但实际上并没有达到预期的效果。看了一些资料,我个人得出的结论是,为了减少重绘的次数,浏览器会维护一个flush队列,需要重排的时候把操作放入队列中,等到排队的时候再重绘一次满的。所以上面两句话被浏览器合并写在一起了。为此,我尝试了两种解决方案:使用setTimeoutsetTimeout(function(){$('.slider-underline').addClass('underline-bezier');},0);这个方法写的时候只是试探性的,但是达到了预期的效果。具体是因为浏览器任务插入的问题还是执行函数触发重绘前flush队列满了,不太清楚。Forceflushqueueheadertime当获取到以下属性时,浏览器会强制浏览器提前flushqueue,以获取准确的位置。offsetTop,offsetLeft,offsetWidth,offsetHeightscrollTop/Left/Width/HeightclientTop/Left/Width/Heightwidth,heightgetComputedStyle()/currentStyle所以把js改成:$('.slider-underline').css('left',active_position+'px');varget_left=$('.slider-underline').css('left');$('.slider-underline').addClass('underline-bezier');可以达到预期的效果。