【问题标题】:Unexpected jump while changing position from absolute to fixed, why?将位置从绝对位置更改为固定位置时意外跳转,为什么?
【发布时间】:2018-01-13 23:38:25
【问题描述】:

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

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

https://jsfiddle.net/addxmkgj/

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

【问题讨论】:

  • 他们“冲了一秒钟”?你能进一步解释一下吗?我在 Firefox 中尝试过,但没有看到任何不需要的结果。
  • @SpyderScript 导航栏和侧边栏容器都会意外移动一会儿。
  • 不要忘记 relative 是相对于它在文档中的位置,而 fixed 和 absolute 都会从正常流程中删除元素。
  • 将标题和问题中的“相对”更改为“绝对”以反映 jsfiddle 和 codepen 上发布的代码。如果您愿意,您可以回滚编辑。

标签: javascript jquery html css


【解决方案1】:

原因

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

此外,滚动事件处理与页面更新不同步:如果鼠标滚轮启动向下滚动,则释放滚轮后可以继续滚动(与触摸事件滚动类似)。在滚动事件处理有机会赶上并改变位置之前,浏览器可以滚动到 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 support sticky position”显示了对 JQuery 插件支持的选择。

推荐

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

【讨论】:

  • 你能带一个显示正确结果的jsfiddle / codepen吗?
猜你喜欢
  • 1970-01-01
  • 2018-08-10
  • 2017-06-12
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 2013-07-13
  • 2018-06-28
  • 1970-01-01
相关资源
最近更新 更多