原因
滚动可以快速生成滚动事件,处理程序可能需要在某种程度上限制滚动事件(例如,在滚动停止后执行代码操作)或者是可以快速执行的相当轻量级的函数。
此外,滚动事件处理与页面更新不同步:如果鼠标滚轮启动向下滚动,则释放滚轮后可以继续滚动(与触摸事件滚动类似)。在滚动事件处理有机会赶上并改变位置之前,浏览器可以滚动到 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 - 支持浏览器的站点访问者将获得最佳体验,那些使用旧版本的浏览器浏览器将获得功能支持。