You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

移动端浏览器中粘性div的overflow:hidden导致无法滚动到底部

视差+滤镜滚动在移动端Chrome的粘性容器异常问题排查与修复

问题概述

需求是实现一个极简页面:核心为一个120vh的粘性div,包含背景图与文本,实现视差滚动+滤镜变化效果。

异常表现

  • 桌面浏览器(含桌面端模拟移动端预览)完全正常
  • 真实移动设备(Pixel 5 + Android Chrome)出现异常:向下滚动后再向上滚动,粘性容器会收缩,导致无法滚动到底部
  • 仅手动触摸滚动触发问题,通过按钮调用scrollToTop/scrollToBottom时无异常

临时缓解方案

已将framer-motion的动画进度范围从[0,1]调整为[0,0.75],但仅能减少问题出现概率,未彻底解决。

问题根源推测

怀疑是position: sticky、overflow: hidden、height: 100vh以及子元素溢出容器这几个属性的组合,触发了移动端Chrome的渲染/布局计算bug。

原因分析

  1. 移动端视口动态变化:Android Chrome在滚动时会隐藏/显示地址栏,导致视口高度动态变化,100vh的容器会跟随调整,但粘性定位元素的锚定逻辑在这种动态变化下出现计算偏差
  2. 触摸滚动的增量重绘:手动触摸滚动时,浏览器为了性能采用增量式布局重绘,粘性容器的尺寸计算未同步更新,导致滚动后容器异常收缩;而scrollTo类API触发的滚动是一次性完成布局计算,不会触发该bug
  3. overflow:hidden与粘性元素的冲突:父容器设置overflow:hidden后,移动端Chrome对粘性元素的溢出判定逻辑异常,滚动后无法正确恢复容器的原始尺寸

修复方案

方案1:替换100vh为动态适配的高度单位

  • 使用现代CSS的dvh(动态视口高度)替代100vh,自动适配移动端视口的动态变化:
    .viewport-container {
      height: 100dvh;
      overflow: auto;
    }
    
  • 如需兼容不支持dvh的旧版浏览器,用JS动态计算视口高度:
    function updateViewportHeight() {
      const vh = window.innerHeight * 0.01;
      document.documentElement.style.setProperty('--vh', `${vh}px`);
    }
    updateViewportHeight();
    window.addEventListener('resize', updateViewportHeight);
    window.addEventListener('orientationchange', updateViewportHeight);
    
    对应CSS使用:
    .viewport-container {
      height: calc(var(--vh, 1vh) * 100);
    }
    

方案2:调整粘性定位与溢出裁剪的实现

  • 移除父容器的overflow:hidden,改用clip-path实现裁剪效果,避免干扰粘性元素的布局计算:
    .sticky-container {
      position: sticky;
      top: 0;
      clip-path: inset(0 0 0 0); /* 等效于overflow:hidden,但布局逻辑不同 */
    }
    
  • 给粘性容器显式设置min-height: 120vh,确保滚动后容器不会因布局计算错误收缩:
    .sticky-container {
      height: 120vh;
      min-height: 120vh;
    }
    

方案3:优化动画进度的计算逻辑

  • 将framer-motion的动画进度与实际可滚动距离绑定,而非使用固定的0-1范围,同时限制进度上限避免触发异常布局:
    const scrollableHeight = document.documentElement.scrollHeight - window.innerHeight;
    const scrollProgress = window.scrollY / scrollableHeight;
    // 限制进度最大为0.95,避免触发布局边界的异常
    const clampedProgress = Math.min(Math.max(scrollProgress, 0), 0.95);
    

内容的提问来源于stack exchange,提问作者Moritz Roessler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 12:33:30