背景
俗话说,产品设计有三宝:弹窗、浮层加引导。可见“弹窗”在产品设计中的重要性。对于前端开发者来说,实现一个基础的模态框(Modal)并不难,可一旦模态框内部出现可滚动内容,各种意想不到的问题就会接踵而至——其中最为典型的,就是“滚动穿透”。
什么是滚动穿透?
滚动穿透指的是:当我们在顶层弹窗中执行滑动操作时,实际滚动的是底层页面的内容。这种体验非常影响交互,也常让用户感到困惑。
解决方案分析
解决滚动穿透的思路通常有两种:改变顶层或改变底层。
1. 改变顶层(不推荐)
一种自然的想法是阻止顶层的事件继续传播。例如,给遮罩层(蒙层)绑定 catchtouchmove 事件。但这种方法在部分场景下并不生效,因此并不是一个可靠的通用方案。
2. 改变底层(推荐)
既然问题是底层内容跟随滚动,那么只要在弹窗打开时禁止底层页面滚动,问题就迎刃而解。
具体实现方案
🟡 不成熟的方案
-
将底层页面的最外层 view 设置为 position: fixed,但这会导致页面滚动位置丢失,回到顶部。
-
另一种方式是:在打开弹窗前记录当前滚动位置,关闭弹窗后使用 wx.pageScrollTo 滚动回原位置。这种方法实现较为繁琐,且体验不够流畅。
✅ 成熟的方案
方案一:使用 page-meta 组件
通过微信小程序提供的 page-meta 组件,我们可以直接控制页面根容器的样式,类似于在 H5 中设置 body { overflow: hidden; }。
我们可以动态设置 overflow 属性为 hidden 或 auto,来控制页面是否可滚动。
方案二:使用 wx.setPageStyle 方法
这是一个更灵活的 API,特别适合在组件内部(如封装好的弹窗组件)使用,无需额外编写 page-meta 结构。
wx.setPageStyle({
style: {
overflow: 'hidden' // 或 'auto'
}
})
代码示例
这里提供一个可供测试的代码片段,帮助你快速上手:
👉 点击查看代码片段
拓展:支付宝小程序的情况
支付宝小程序虽然也支持 page-meta 组件,但由于其 WebView 内核限制(版本 69),设置 overflow: hidden 并不能完全阻止底层滚动。
支付宝团队为此专门提供了新的 API:my.setPageScrollable,用于精确控制页面是否可滚动。
my.setPageScrollable({
scrollable: false,
success: (res) => console.log(res),
fail: (err) => console.log(err)
})
更新(2025.06.18)
该 API 已正式开放。不过目前测试发现:在 安卓端 设置禁止滚动后,弹窗内的可滚动区域也会被一并禁止;iOS 端 则表现正常,仅底层页面被锁定。
原因分析:
安卓与 iOS 在滚动禁止的层级控制上存在系统级差异:
- 安卓 采用 Webview 级别的滚动限制,生效时整个页面(包括所有弹层)均不可滚动;
- iOS 采用组件级控制,能智能区分层级,仅锁定底层页面而保持弹窗内部可滚动。

我就发现不管什么东西用到极致就会发现他的bug,完事官方还不给解决
跟 web 里面的 Helmet 组件有点儿类似,可以用来修改 page-meta 信息。
page-meta 组件在 iPhone8 上无效,大佬们有遇到这种兼容问题吗?
<!--首页--><wxs src="../../../../page/wxs/util.wxs" module="mUtil"></wxs><page-meta page-style="overflow: {{pageOverflowVisible ? 'visible' : 'hidden'}}" /><parent-component><child-component></child-component></parent-component><!-- 弹窗在 child-component 组件内显示隐藏-->弹窗弹出时,直接把底部的scroll-view的scroll-y设置为false,就可以阻止底层滚动了呀,不需要用这个page-meta吧
感谢大佬。之前用catchtouchmove解决,后来弹窗变复杂就突然不好使了。。这个方法确实简单快捷
麻烦问下pageMeta在taro中怎么使用啊?
老哥 这个方法很稳
https://developers.weixin.qq.com/community/develop/article/doc/000e40918dc420f5f61c2001a56013,这一篇写得特别详细,楼主也可以看看!
uni 解决方案:<scroll-view class="select-list" scroll-y @touchmove.stop>
支付宝怎么操作?没在支付宝文档找到disableScroll 这个api
方法名叫:my.setPageScrollable() 目前还没上线。