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

1 html javascript css jquery

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

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

https://jsfiddle.net/addxmkgj/

(在大屏幕中尽可能 大地调整屏幕大小)——编辑—— 也添加了https://codepen.io/anon/pen/dJKBPe codepen 链接。

tra*_*r53 5

原因

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

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

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

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

实验疗法

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

.side-bar {
position: absolute;
height: 150%;
... /* more declarations */
Run Code Online (Sandbox Code Playgroud)

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

可以通过使用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)
});
Run Code Online (Sandbox Code Playgroud)

这段代码显示了跳跃减少的改进,但并不完美。它不是特别的 JQuery 解决方案,requestAnimationFrame直接调用。

当然,一种选择是在给定浏览器时间限制的情况下什么都不做。


更新

这个滚动链接效果的 MDN 指南比我能更好地解释根本原因问题:

大多数浏览器现在支持某种异步滚动......视觉滚动位置在合成器线程中更新,并且在 DOM 中更新滚动事件并在主线程上触发之前对用户可见......这可能导致延迟、卡顿或紧张的效果——简而言之,这是我们想要避免的。

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

未来的解决方案是使用sticky定位(请参阅上面的滚动效果指南或CSS 位置指南。但是position:sticky在相对位置和固定位置之间交换,因此 HTML 需要重新设计以适应这一点。

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

推荐

可能最好的折衷方案可能是重新设计 HTML 以使用粘性定位并包含一个 JQuery 插件,该插件在可用时使用本机支持或在不支持时使用 polyfill - 支持浏览器的站点访问者将获得最佳体验,使用旧浏览器的访问者将获得功能支持。