在将位置从绝对位置更改为固定位置时出现意外跳转,为什么?

时间:2018-01-13 23:38:26

标签: javascript jquery html css

首先,我想说这不是内容跳跃!

我有一个导航栏和侧边栏都有absolute位置。用户滚动100像素后,我将它们都更改为fixed。但奇怪的行动发生了(并不总是!)。导航栏和侧边栏的包装器冲洗一秒钟。我用不同的浏览器测试它,它不依赖于浏览器。我试图重现这个小提琴中的情况:

https://jsfiddle.net/addxmkgj/

(尽可能大的屏幕调整屏幕大屏幕) - 编辑 - https://codepen.io/anon/pen/dJKBPe codepen链接也加入了。

1 个答案:

答案 0 :(得分:4)

原因

滚动可以快速生成滚动事件,处理程序可能需要在某种程度上限制滚动事件(例如,在滚动停止后执行代码操作),或者是可以快速执行的相当轻量级的函数。

此外,滚动事件处理与页面更新不同步:如果鼠标滚轮启动向下滚动,则在释放滚轮后可以继续滚动(并且类似于触摸事件滚动)。在滚动事件处理有机会赶上并改变定位之前,浏览器可以在100px的顶部位置下滚动。

结果是标题从部分屏幕外跳下来占据屏幕顶部的固定位置。滚动动作越快(或浏览器越忙),跳跃的可能性就越大。

桌面浏览的一个辅助效果是,当侧栏面板向上滚动超过屏幕顶部并再次向下移动时,在固定定位生效之前,可见的白色屏幕会在侧栏下方“闪烁”。

实验性补救措施

通过增加容器的高度,可以减少侧杆的闪光但不一定完全消除。将可见溢出的高度更改为150%会取得一些成功:

.side-bar {
position: absolute;
height: 150%;
... /* more declarations */

这可能会或可能不会与应用程序要求发生冲突。

通过使用requestAnimationFrame回调来监控scrollTop值并根据需要更改定位,可以实现一些导航栏跳转缓解。这不会使用滚动事件处理:

$(document).ready(function() {
    $(window).resize(function() {
        if( $(window).width() > 850) {
            $('.navbar').css('display', 'block');   
        } else {
            $('.navbar').css('display', 'none');
        }
    });
    scrollTo(0, 0);
    var num = 100;
    var bAbsolute = true;
    function checkScroll() {
        var newTop = $(window).scrollTop();
        if( bAbsolute && newTop >= num) {
             $('.navbar').css('position', 'fixed');
            $('.navbar').css('top', '0');
            $('.side-bar').css('position', 'fixed');            
            $('.side-bar').css('top', '0');
            bAbsolute = false;
        }
        if( !bAbsolute && newTop < num) {
            $('.navbar').css('position', 'absolute');
             $('.side-bar').css('position', 'absolute');
             $('.navbar').css('top', '100px');
             $('.side-bar').css('top', '100px');
            bAbsolute = true;
        }
        requestAnimationFrame( checkScroll);

    } 
    requestAnimationFrame( checkScroll)
});

此代码显示跳跃减少有所改善,但并不完美。它不是特别的JQuery解决方案,直接调用requestAnimationFrame

当然,一个选择是在浏览器时序限制下不执行任何操作。

<小时/>

更新

这个MDN guide for Scroll linked effects比我能够更好地解释根本原因问题:

  

大多数浏览器现在支持某种异步滚动....可视滚动位置在合成器线程中更新,并且在DOM中更新滚动事件并在主线程上触发之前,用户可以看到...这可能会导致效果变得迟钝,笨拙或紧张 - 简而言之,我们想要避免这种情况。

因此绝对定位的元素可以在滚动处理程序被通知新的滚动位置之前滚动屏幕(在某种程度上)。

前进的解决方案是使用sticky定位(请参阅上面的滚动效果指南或CSS position guide。但是position:sticky在相对位置和固定位置之间切换,因此HTML需要重新设计到容纳这个。

粘性定位也是2018年1月的前沿技术,尚未推荐用于MDN的生产。对“JQuery支持粘性位置”的网络搜索显示了JQuery插件支持的选择。

建议

最好的妥协可能是重新设计HTML以使用粘性定位,并包括一个JQuery插件,该插件在可用时使用本机支持,或者在没有时使用polyfill - 具有支持浏览器的网站访问者将获得最佳体验,具有旧版本的访问者浏览器将获得功能支持。