【问题标题】:DOM element position slow while scrolling + difference between scrollbar-scrolling and mouse/touchpad-scrolling滚动时DOM元素位置变慢+滚动条滚动和鼠标/触摸板滚动之间的区别
【发布时间】:2015-01-18 10:30:01
【问题描述】:

我在使用 Safari 时遇到了一点问题 - 当我想在滚动事件上更新 DOM 元素的位置时,Safari 似乎跟不上这些变化(导致跳动的滞后效应)。 我在其他浏览器(Chrome、FF、IE8+)上检查过,这似乎是 Safari 特有的。

我做了一个 jsfiddle 来说明我的问题:

$("#container").on("scroll", function() {
    $("#slide").css({
        left: $("#container").scrollLeft() + "px"
    });
    
    var leftPos = 0;
    for(var i = 0; i < 2000 ; i++) {
        leftPos = $("#slide").css("left");
    }  
    $("#info").text(leftPos); 
});

http://jsfiddle.net/a4b86et3/2/

如您所见,我在每次滚动时添加了一个额外的 DOM 读取循环,以模拟每次事件发生时的“更多操作正在进行”,因为这种机制是更大项目的一部分,其中包含许多其他 DOM 操作。 (注意,除了 Safari,这个例子在任何地方都能流畅运行)

另外,我使用jQuery只是为了方便,实际项目使用的是纯js。

我设法部分解决了这个问题

通过将left = x 属性更改为transform = translate3d(x,0,0),这样浏览器就会使用GPU。

$("#container").on("scroll", function() {
    $("#slide").css({
        '-webkit-transform': 'translate3d(' + $("#container").scrollLeft() + 'px, 0, 0)'
    });
    
    var leftPos = 0;
    for(var i = 0; i < 1900 ; i++) {
        leftPos = $("#slide").css("left");
    }  
    $("#info").text(leftPos);
    
});

http://jsfiddle.net/a4b86et3/3/

但是,有时我在滚动时仍然会遇到轻微的延迟/故障。

但是,更重要的是,当我使用鼠标滚动或触摸板时,此修复不会影响滚动!虽然拖动滚动条效果更好,但使用上述任何方法都会让我回到最初的问题。

任何想法为什么会发生这种情况以及如何解决它?


tl;博士; - Safari 在滚动时更改元素位置时速度很慢;使用鼠标滚动/触摸板时 translate3d 似乎无法正常工作。

【问题讨论】:

    标签: javascript performance safari scroll webkit


    【解决方案1】:

    我遇到了完全相同的问题,我花了一些时间来解决问题。这是一个更新的 jsfiddle,向您展示如何在 Safari 中解决该问题:http://jsfiddle.net/a4b86et3/4/

    function handle_scroll() {
      $("#slide").css({
        '-webkit-transform': 'translate3d(' + $("#container").scrollLeft() + 'px, 0, 0)'
      });
    
      var leftPos = 0;
      for(var i = 0; i < 1900 ; i++) {
        leftPos = $("#slide").css("left");
      }  
      $("#info").text(leftPos);
    }
    
    $("#container").on("scroll", handle_scroll);
    $("#container").on('mousewheel', function(e) {
      e.preventDefault()
    
      var maxX = this.scrollWidth  - this.offsetWidth
      var maxY = this.scrollHeight - this.offsetHeight
      this.scrollTop  = Math.max(0, Math.min(maxY, this.scrollTop  - e.originalEvent.wheelDeltaY))
      this.scrollLeft = Math.max(0, Math.min(maxX, this.scrollLeft + e.originalEvent.wheelDeltaX))
    
      handle_scroll(e)
    })
    

    简而言之:如果您自己处理鼠标滚轮事件,在那里计算正确的滚动值,然后调用您的处理程序代码,事情就开始工作了。

    我不确定为什么 Safari 会让你跳过这个环节,但幸运的是,修复并没有涉及太多。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多