
Telegram WebApp 默认将页面顶部下拉手势识别为“关闭应用”操作,当网页存在非自然滚动限制(如固定高度容器)时会触发误判;通过移除 height 和 max-height 等强制高度约束,恢复文档自然流式滚动,即可有效禁用该手势拦截。
telegram webapp 默认将页面顶部下拉手势识别为“关闭应用”操作,当网页存在非自然滚动限制(如固定高度容器)时会触发误判;通过移除 `height` 和 `max-height` 等强制高度约束,恢复文档自然流式滚动,即可有效禁用该手势拦截。
在使用 Bubble.io、Flutter 或其他低代码/前端框架构建 Telegram WebApp 时,一个高频且隐蔽的问题是:用户在页面顶部轻微下拉(scroll up),整个 WebApp 突然被 Telegram 强制收起或最小化。这并非 Bug,而是 Telegram 官方设计的「安全关闭手势」——但其触发条件高度依赖页面的滚动行为是否符合“原生 WebView 行为”。
关键原理在于:Telegram 仅在检测到 页面无法继续向上滚动(即 scrollTop === 0 且内容未溢出视口) 时,才将下拉动作解释为关闭指令。一旦你的布局中存在如下 CSS 设置:
.container {
height: 100vh; /* ❌ 危险:强制截断滚动 */
max-height: 600px; /* ❌ 危险:抑制内容自然溢出 */
overflow: hidden; /* ❌ 危险:隐藏滚动能力 */
}
即使实际内容远超视口高度,浏览器因高度锁定而无法产生 scroll 事件或正确报告 scrollTop,Telegram 就会误判为“已到顶”,从而激活关闭手势。
✅ 正确做法是让文档拥有自然的、可测量的滚动上下文:
- 移除所有父容器上的 height / max-height(尤其是 100vh、100% 等全屏占位写法);
- 使用 min-height: 100vh 替代 height: 100vh;
- 确保 和 无 overflow: hidden;
- 若需自定义滚动区域(如侧边栏、列表),请仅对局部容器启用 overflow-y: auto,并为其设置 max-height(而非整个页面);
示例修复后结构:
<!-- ✅ 推荐:根容器不设死高度 -->
<div class="app-wrapper">
<!-- Bubble.io 生成的内容区域 -->
<header>...</header><main style="overflow-y: auto; max-height: calc(100vh - 120px);"><!-- ✅ 局部滚动,不影响全局 scroll 检测 --><!-- 内容可长可短,body 仍能自然滚动 --></main>
</div>
⚠️ 注意事项:
- 不要依赖 preventDefault() 拦截 touchmove —— Telegram 关闭手势发生在 native 层,JS 无法阻止;
- 避免使用 position: fixed 覆盖整个视口的遮罩层(如加载弹窗),它会破坏滚动锚点;
- 在 Telegram WebApp 中,window.innerHeight 可能动态变化(如键盘弹出),优先使用 100dvh(如支持)或 JS 动态计算安全高度;
- 测试时务必在真实 Telegram iOS/Android 客户端中验证,Chrome 模拟器无法复现该手势逻辑。
总结:这不是兼容性问题,而是滚动语义的对齐问题。Telegram 的关闭机制本质是“滚动边界探测”,而非事件监听。只要确保 →
→ 主内容链路具备真实的、可测量的垂直滚动能力,下拉手势就会自动降级为普通页面滚动,关闭行为自然消失。










