移动端Safari:添加禁止滚动样式时避免页面滚动位置重置至顶部
问题描述
我在网站中实现了一个具备隐藏、最小化、全屏三种状态的弹窗。当弹窗处于全屏状态时,我通过给页面添加noscroll类来禁止背后页面滚动,退出全屏时移除该类。对应的CSS代码如下:
.noscroll { height: 100vh; height: 100svh; overflow: hidden; }
该方案在桌面端表现正常,但在移动端Safari浏览器中,添加noscroll类后页面滚动位置会被重置至顶部。我尝试过两种方案但均不符合需求:
- 为
noscroll类添加position: fixed属性——在我的场景中无效; - 保存滚动位置,弹窗关闭后恢复——但会触发类似Twitter或Instagram的顶部下拉刷新,无法解决根本问题。
请问是否存在既能避免页面滚动位置跳转,又能禁止页面滚动的方法?
可行解决方案
针对移动端Safari的兼容性问题,推荐两种兼顾需求的实现方式:
方案一:CSS变量+Sticky定位锁定滚动位置
通过CSS变量实时记录页面滚动距离,结合position: sticky定位避免Safari重置滚动位置,同时保留overflow: hidden禁止滚动:
- 调整
noscroll类的CSS代码:
.noscroll { overflow: hidden; position: sticky; top: calc(0px - var(--scroll-top, 0px)); }
- 添加JavaScript代码实时更新滚动距离变量:
// 监听页面滚动,将滚动距离存入CSS变量 window.addEventListener('scroll', () => { document.documentElement.style.setProperty('--scroll-top', `${window.scrollY}px`); }); // 打开全屏弹窗时添加类 function openFullscreenModal() { document.body.classList.add('noscroll'); } // 关闭全屏弹窗时移除类 function closeFullscreenModal() { document.body.classList.remove('noscroll'); }
这种方式利用sticky定位特性让body保持当前滚动位置,同时overflow: hidden禁止滚动,不会触发下拉刷新。
方案二:阻止body的touchmove事件(排除弹窗元素)
通过JavaScript拦截非弹窗区域的触摸滚动事件,允许弹窗内部正常滚动(若有需求),同时保留overflow: hidden作为兜底:
- 保留原有的
noscroll类CSS:
.noscroll { height: 100vh; height: 100svh; overflow: hidden; }
- 添加事件监听控制滚动:
function preventBodyScroll(event) { // 仅当触摸事件不是来自弹窗及其子元素时,阻止默认滚动行为 if (!event.target.closest('.modal')) { event.preventDefault(); } } // 打开全屏弹窗时绑定事件(passive设为false才能阻止默认行为) function openFullscreenModal() { document.body.classList.add('noscroll'); document.addEventListener('touchmove', preventBodyScroll, { passive: false }); } // 关闭全屏弹窗时解绑事件并移除类 function closeFullscreenModal() { document.body.classList.remove('noscroll'); document.removeEventListener('touchmove', preventBodyScroll); }
该方案直接拦截非弹窗区域的触摸滚动,既不会重置页面滚动位置,也能避免触发顶部下拉刷新。
内容的提问来源于stack exchange,提问作者user23873005
相关产品推荐
相关产品推荐

