IE 11平滑滚动未触发中间滚动事件

22

如果我们创建一个简单的测试案例,例如:

document.documentElement.addEventListener('scroll', function() {
    console.log(document.documentElement.scrollTop);
});

然后使用滚动条通过点击轨道或使用PageDown/PageUp进行滚动,然后我们会发现在滚动动画结束时只会收到一个事件。

理论上我可以通过模拟滚动事件来解决其中一些行为问题。以下是使用jQuery和Underscore的示例代码:

$(function () {
    var $document = $(document), until = 0;

    var throttleScroll = _.throttle(function () {
        $document.scroll();
        if (+new Date < until) {
            setTimeout(throttleScroll, 50);
        }
    }, 50);

    $document.keydown(function (evt) {
        if (evt.which === 33 || evt.which === 34) {
            until = +new Date + 300;
            throttleScroll();
        }
    });
});

但它仍然无法正常工作。我们只能获得原始 scrollTop 和目标 scrollTop 的滚动事件,没有中间的值。

如果每隔10ms使用 console.log(document.documentElement.scrollTop),那么我们可以看到IE在滚动时不更新 scrollTop

如果我们想要将某些内容与滚动位置“固定”,这非常令人沮丧。在IE中会出现抖动。

我没有观察到任何其他浏览器上出现这种行为,也没有在之前的IE版本上进行测试。

如果有人找到了修复IE行为的方法(也许有一个神奇的CSS可以关闭IE 11中的平滑滚动?),那么我非常希望听到!

谢谢 :-)


什么都没有吗?我就知道。 - daniel.gindi
自从iOS Safari首次发布以来,我没有在任何其他浏览器上观察到这种行为。我怀疑IE团队认为如果这能给他们带来性能优势,他们可以遵循这个先例。Android Chrome会相当频繁地发送滚动事件,但不足以消除卡顿。 - stephband
我不确定我们能否捕获所有的滚动触发器并替换为手动触发器。会尝试一下... - daniel.gindi
IE11。我猜测你的安装中由于某些原因禁用了平滑滚动。 - daniel.gindi
刚遇到了类似的问题。我也想知道这个问题的答案。 - scooterlord
显示剩余9条评论
4个回答

9

您说:“如果有人找到了修复IE行为的方法(也许有一个神奇的CSS可以关闭IE 11中的平滑滚动?),那么我非常想听听!"

这并不能关闭它,但这是我用来解决在固定元素中使用ie时平滑滚动问题的方法。

if(navigator.userAgent.match(/Trident\/7\./)) {
    $('body').on("mousewheel", function ( event ) {
        event.preventDefault();
        var wd = event.wheelDelta;
        var csp = window.pageYOffset;
        window.scrollTo(0, csp - wd);
    });
}

看起来不错 - 可以阻止IE 11继续滚动...你是否尝试创建一个解决方案,也可以修复页面的上/下滚动? - daniel.gindi
1
如果我们能够添加对触摸式(滑动)滚动、键盘上下和触控板的支持,那将是非常棒的。我遇到的错误是在使用background-attachment: fixed时产生的。 - patrickzdb

6
您所描述的问题只限于运行在Windows 7上的Internet Explorer 11实例。这个问题不会影响IE 11诞生的平台,即Windows 8.1。看起来IE 11在Windows 7上属于其他提到的滚动实现类别之一。虽然这不是理想情况,但暂时我们必须与之共存并解决。
我将继续研究这个问题;事实上,我刚从壁橱里找出了一台Windows 7机器,准备明天一早设置好以便进一步调查。虽然我们无法直接解决这个问题,但或许有一种方法可以绕过这个问题本身。
待续。

1
@daniel.gindi 是的,我是Internet Explorer团队的程序经理。如果您有一个由此导致崩溃的演示文稿,我会很感激您提供链接。有些东西可以进行实验,这将使进一步的调查更加有成果。 - Sampson
2
据我所理解,@Jonathan Sampson,问题在于IE11在平滑滚动动画期间不触发滚动事件。因此,我们看到页面滚动动画,但在此动画期间我们没有得到滚动事件,因此所有需要在滚动事件上更新的内容实际上并未更新,只有在动画结束时才会立即更新,当滚动事件被触发时。这使得在页面已经动画化之后,需要更新的内容突然跳到原地,从而产生了不稳定的行为。 - Andrey
1
@Jonathan Sampson 在Win 8和IE 10.0.9200.16384上,我看到这个fiddle在动画期间没有更新div文本。请参见:http://goo.gl/tYYilU 在Win 8.1和IE 11.0.13上,这个fiddle在动画期间更新div文本,但在实际的示例中,在滚动动画期间仍然会出现跳跃,请参见:http://goo.gl/7qfPkc,这意味着可能在动画滚动事件分派时速率不足或其他原因,但在Win8.1上的IE11中显然存在问题。 与Firefox平滑滚动相比,元素可以平稳地固定,就像我们手动拖动滚动条一样:http://goo.gl/h07Ty8 - Andrey
1
@Jonathan Sampson,更清晰的例子:http://jsbin.com/bulivizozi/1。在这里,我们还更新了元素的顶部位置。在Win 8.1和IE 11.0.13上,尽管滚动事件正在触发,但元素在滚动动画时会抖动。如果我们手动拖动滚动条,则元素不会抖动:http://goo.gl/wliFqV。但我正在使用来自modern.IE VM的win 8.1,并且已经有一段时间没有更新了。也许这不是最新的Windows版本上的问题... - Andrey
@JonathanSampson 有什么消息吗? - daniel.gindi
显示剩余4条评论

1

是的,那可能是一个解决方案(或者是一个hack),我需要进行一些测试来看它如何处理触摸事件... - daniel.gindi

-1

看起来有一篇关于IE和强制屏幕“绘制”以帮助拖放的文章。似乎与大多数性能方面的努力相反,但可能有效?https://dev59.com/xnM_5IYBdhLWcg3wZSI6#12395506(代码来自https://stackoverflow.com/users/315083/george

function cleanDisplay() {
    var c = document.createElement('div');
    c.innerHTML = 'x';
    c.style.visibility = 'hidden';
    c.style.height = '1px';
    document.body.insertBefore(c, document.body.firstChild);
    window.setTimeout(function() {document.body.removeChild(c)}, 1);
}

你可以尝试使用CSS动画,让浏览器处理动画/过渡效果。例如,在滚动时应用show/hide类和CSS动画。
.hide-remove {
    -webkit-animation: bounceIn 2.5s;
    animation: bounceIn 2.5s;
}

.hide-add {
    -webkit-animation: flipOutX 2.5s;
    animation: flipOutX 2.5s;
    display: block !important;
}

如果没有浏览器处理动画(使用创意 CSS),关键帧和 JS 性能可能会提供线索。此外,我看到过几个网站在滚动结束后“重新出现”导航栏。


那会有什么帮助呢?重绘与滚动无关。如果这样做可以起作用,你是否建议每隔X毫秒就让浏览器重绘一次,无论它是否正在滚动? - daniel.gindi
我理解问题是“移动菜单”看起来很卡顿,因此建议重新绘制以获取位置信息。所有浏览器在滚动鼠标时都会进行大跳跃移动。 - s6712
不,问题不在于获取JavaScript onscroll事件。 - daniel.gindi

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