浏览器窗口大小调整时如何更新全屏菜单修复错位问题
问题现象
实现的GSAP全屏菜单在打开状态下调整浏览器窗口大小时存在显示异常:关闭菜单的位移动画基于调整前的旧窗口宽度计算,打开菜单后放大浏览器窗口再执行关闭操作,屏幕上会残留部分菜单内容。
复现步骤:
- 缩小浏览器宽度后刷新页面
- 触发打开菜单操作
- 增大浏览器宽度后触发关闭菜单操作,即可看到菜单残留的异常表现
问题根因
异常由两点共同导致:
- 初始CSS给菜单设置的隐藏状态偏移为
translateX(-100vw),GSAP初始化时间线时会将该值读取为固定像素值缓存,窗口尺寸变化后,缓存的旧像素偏移量和新视口宽度不匹配,反向播放关闭动画时无法将菜单完全移出可视区域 - 窗口触发resize事件时没有同步更新动画的计算参数,动画全程使用初始化时读取的旧值计算位移
修复方案
CSS调整
将菜单初始偏移的vw单位替换为相对于元素自身的百分比单位。由于菜单为fixed定位、inset设为0,自身宽度完全等于视口宽度,-100%偏移可以保证任意窗口尺寸下,菜单刚好完全移出屏幕左侧:
.menu { height: 100vh; position: fixed; inset: 0; background-color: #d0ff00; color: #d0ff00; /* 替换原translateX(-100vw) */ transform: translateX(-100%); overflow-y: hidden; }
其余CSS规则保持不变即可。
JS逻辑调整
增加resize事件监听,加入防抖逻辑避免事件频繁触发导致性能损耗,窗口尺寸变化时根据菜单当前开合状态同步校准动画状态:
const menuToggleOpen = document.querySelector("#menu-toggle-open"); const menuToggleClose = document.querySelector("#menu-toggle-close"); const menu = document.querySelector(".menu"); const tl = gsap.timeline({ paused: true }); tl.to(".menu", { x: 0, duration: 0.6, ease: "expo.inOut" }); tl.from(".menu nav a", { y: 40, opacity: 0, duration: 0.4, ease: "expo.out", stagger: 0.1 }); tl.from(".social", { y: 40, opacity: 0, duration: 0.4, ease: "expo.out" }); menuToggleOpen.addEventListener("click", () => tl.play()); menuToggleClose.addEventListener("click", () => tl.reverse()); // 新增resize校准逻辑 let resizeDebounce = null; window.addEventListener('resize', () => { clearTimeout(resizeDebounce); resizeDebounce = setTimeout(() => { if (tl.progress() === 1) { // 菜单处于完全打开状态时,强制校准位置到可视区域 gsap.set(menu, { x: 0 }); return; } // 菜单处于关闭/动画播放过程中,直接重置时间线到初始关闭状态,重新读取当前正确的偏移值 tl.pause(0); }, 100); });
修改完成后,任意窗口尺寸下调整大小再操作菜单,开关动画都能正常运行,不会出现菜单残留屏幕的问题。
内容的提问来源于stack exchange,提问作者gjjr
相关产品推荐
相关产品推荐

