本文详解如何使用原生 javascript 和 jquery 实现一个居中固定、随滚动精准触发显隐的 dom 元素:在页面向下滚动超过目标区域顶部 + 偏移阈值时显示,再向下滚动额外距离后自动隐藏,并支持向上回滚时及时收起。
本文详解如何使用原生 javascript 和 jquery 实现一个居中固定、随滚动精准触发显隐的 dom 元素:在页面向下滚动超过目标区域顶部 + 偏移阈值时显示,再向下滚动额外距离后自动隐藏,并支持向上回滚时及时收起。
要实现“滚动出现 → 继续滚动隐藏 → 回滚再次隐藏”的精确控制,关键在于解耦触发逻辑与状态记录。原始代码中 scrollDistance 仅记录首次显示时的滚动位置,但未定义“二次隐藏”的绝对阈值,导致向下滚动时无法触发隐藏;同时混合使用 fadeIn/fadeOut 与 display 切换,易引发 CSS 过渡冲突。
以下是优化后的完整解决方案(兼容 jQuery 且推荐升级至原生事件提升性能):
✅ 正确逻辑设计
- 显示条件:scrollTop > offsetTop + showThreshold
-
隐藏条件(双重保障):
- 向上回滚:scrollTop
- 向下持续滚动:scrollTop > offsetTop + showThreshold + hideDistance
- 居中定位:使用 position: fixed + transform: translateX(-50%) 确保响应式居中,避免 left: 50% 在缩放/滚动时偏移。
✅ 推荐实现(原生 JS + CSS 优化)
<style>
#first { height: 200px; background: #eee; }
#second { height: 2800px; background: rgba(0,0,0,0.3); }
#show {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
z-index: 1000;
padding: 12px 24px;
background: #fff;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
</style><section id="first"><h1>First</h1></section><section id="second"><h1>Second</h1>
<div id="show">Hey!</div></section><script>
const $show = document.getElementById('show');
const $second = document.getElementById('second');
const offsetTop = $second.getBoundingClientRect().top + window.scrollY;
const SHOW_THRESHOLD = 100; // 出现偏移量(px)
const HIDE_DISTANCE = 300; // 出现后继续滚动多少 px 隐藏
const HIDE_BACK_THRESHOLD = 50; // 向上回滚多少 px 隐藏
let isVisible = false;
function updateVisibility() {
const scrollTop = window.scrollY;
const showTrigger = offsetTop + SHOW_THRESHOLD;
const hideDownTrigger = showTrigger + HIDE_DISTANCE;
const hideUpTrigger = offsetTop - HIDE_BACK_THRESHOLD;
if (scrollTop > showTrigger && !isVisible) {
$show.style.display = 'block';
isVisible = true;
} else if (
isVisible &&
(scrollTop > hideDownTrigger || scrollTop < hideUpTrigger)
) {
$show.style.display = 'none';
isVisible = false;
}
}
// 使用节流优化性能(可选)
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
updateVisibility();
ticking = false;
});
ticking = true;
}
});
// 初始化定位(防止窗口 resize 后错位)
function centerElement() {
const winH = window.innerHeight;
const elH = $show.offsetHeight;
$show.style.top = `${(winH - elH) / 2}px`;
}
centerElement();
window.addEventListener('resize', centerElement);
</script>
⚠️ 注意事项
- 避免混用 jQuery 动画与原生 display:fadeIn() 会内联设置 opacity 和 display,若后续用 css('display','none') 强制覆盖,可能导致过渡中断或闪烁。统一用 display 控制显隐更可控。
- offset().top vs getBoundingClientRect():后者返回视口坐标,需加 scrollY 转为文档坐标,但更稳定(不受父容器 transform 影响)。
- 移动端兼容性:requestAnimationFrame 节流在 iOS Safari 中表现更佳;如需平滑淡入,可改用 CSS transition: opacity .2s 配合 opacity 切换。
- 性能提示:避免在 scroll 中频繁调用 offsetHeight 或 getBoundingClientRect(),已通过 resize 事件单独处理尺寸更新。
该方案彻底解决“向下滚动不隐藏”问题,逻辑清晰、可配置性强,适用于导航提示、浮动按钮、广告横幅等场景。










