JQuery在Chrome中的scrollTop动画不流畅

3

我有一个元素,根据滚动位置应用一些基本的过渡效果。在 Safari 和 Firefox 中预期可以平稳地工作,但在 Chrome 中滚动非常卡顿。

$(document).ready(function($) {
  var divUp = $('.fade');
  var divDown = $('.fade-down');
  $(window).on('scroll', function() {
    var st = $(this).scrollTop();
    divUp.css({ 
        'top'     : -(st/6)+"px", 
        'opacity' : 1 - st/400
    });
    divDown.css({
        'opacity' : 1 - st/400
    }); 
  });
});

我已经逐个注释掉每个CSS属性,但是Chrome仍然很卡顿。这是因为top属性在移动一个相对定位的元素。

有什么方法可以在仍然让Chrome的JS引擎快乐的情况下实现所需的效果?非常感谢您提供任何反馈。


我不确定 st 变量是否包含了你想要的内容。 - ivan.mylyanyk
@GoogleHireMe 它正实现我想要的——同时在滚动时淡化元素并移动其位置。问题只是在 Google Chrome 中有些卡顿。 - SGLVEGAS
@GoogleHireMe Google已经聘用你了吗? - The Muffin Man
@TheMuffinMan 他们正在处理那个问题 ;) - ivan.mylyanyk
1个回答

19

你正在经历布局抖动

改变元素的top属性会使当前布局失效。通常,这会促使浏览器异步重新计算布局(即不立即执行)。

然而,调用scrollTop强制浏览器同步重新布局。因为你在滚动事件处理程序中调用它,所以这会在非常短的时间内重复发生。这个DOM写入-读取序列是卡顿的已知原因之一。

为了提高性能,您需要防止布局抖动。更改CSS的transform(和opacity)属性不会使浏览器的布局无效 - 它们只需要一个合成,这样速度更快。
如果您使用transform: translateY而不是top来进行动画,则浏览器将不需要在每个动画帧上计算昂贵的计算:
divUp.css({ 
  'transform': 'translateY( ' + (-(st/6)) + 'px)', 
  'opacity': 1 - st/400
});

您可以通过设置CSS will-change 属性来帮助浏览器进行过渡的优化:

.your-div {
  will-change: transform;
}

更多阅读:

  • 无卡顿 - 关于提高Web应用程序性能的文章
  • CSS触发器 - 列出浏览器在更改每个CSS属性时需要执行的步骤

太棒了,回答非常详细 - 谢谢!使用transform属性确实提高了性能,但是Safari不再对元素进行过渡。我尝试使用-webkit供应商前缀,但也没有起作用。您有什么建议吗?再次感谢您的帮助! - SGLVEGAS
在其他浏览器中是否正常工作?根据caniuse.com的说法,Safari一直支持-webkit-transform,尽管它还没有不带前缀的支持。此外,似乎jQuery会自动添加前缀,所以这不应该是一个问题。你能否用简化版本创建一个JSFiddle? - joews
好的,我创建了一个简单的 fiddle 来重现这个问题。http://jsfiddle.net/7uusvfwp/ - SGLVEGAS
很好!你找到了打破webkit的方法 :) 好消息是,在其他地方你的过渡非常流畅美观。 - joews
为什么不建议使用以下代码:$('body,html').animate({ scrollTop: 0 },"slow");,你可以将0替换成你需要的数值。 - Legends
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接