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

标签 javascript jquery html css

首先我想说的不是内容跳转!

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

https://jsfiddle.net/addxmkgj/

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

最佳答案

原因

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

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

结果是标题从部分离开屏幕向下跳到屏幕顶部的固定位置。滚动 Action 越快(或浏览器越忙),跳跃越明显。

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

实验疗法

通过增加容器的高度,可以减少但不一定完全消除侧栏的飞边。将高度更改为 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比我能更好地解释问题的根本原因:

most browsers now support some sort of asynchronous scrolling .... the visual scroll position is updated in the compositor thread and is visible to the user before the scroll event is updated in the DOM and fired on the main thread ... This can cause the effect to be laggy, janky, or jittery — in short, something we want to avoid.

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

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

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

推荐

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

关于javascript - 将位置从绝对位置更改为固定位置时意外跳转,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48245326/

相关文章:

javascript - 输入值未传递到 URL

javascript - 如何勾选网格中的勾选列?

JavaScript - 添加 ID 和类

jquery - 等待 Jquery 库加载后再执行外部 javascript 文件

javascript - 在 JavaScript 中使用基于用户输入的条件的问题

html - 易趣 html 特殊标签不起作用?

javascript - 如何从元素内部选择 Bootstrap 选项卡的文本

javascript - 如何将多个信息添加到 JQuery Mobile ListView 中

javascript - 将 textExtraction 与 jQuery 表排序器一起使用时出现问题

javascript - 使用 JQuery 解析 JSON 字符串时出错