移动端横向滚动脚本失效问题求助
移动端横向页面切换滚动问题修复方案
问题还原
你开发的双页面横向切换网站,首页显示时侧边页以0宽度隐藏;点击按钮激活侧边页,脚本触发横向滚动切换,同时隐藏首页,返回流程同理。但在Chrome移动端模式下出现两个问题:
- 脚本无法触发横向滚动,只能手动拖动页面
- 滚动到最右侧时,首页不会自动隐藏
- 临时把
.certOpenLeft类宽度改成10000px能启用滚动,但会彻底破坏页面布局
以下是你提供的简化示例代码:
原HTML代码
<html> <head> <title>HTML Scrolling example</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <div id="horizontalPagesWrapper"> <div class="frontpage pageOpen"> <div class="contentContainer"> <h1>HTML Scrolling example</h1> <button class="infoButton" onclick="ScrollUpAndActivateCertificates()">SIDE PAGE</button> </div> </div> <div class="certificates pageClosed"> <div class="contentContainer"> <h1>Welcome to the side page</h1> <button class="infoButton" onclick="ScrollUpAndActivateFrontpage()">FRONT PAGE</button> </div> </div> </div> </body> </html>
原CSS代码
body { background-color: white; font-family: 'Lato'; margin: 0; padding: 0; backface-visibility: hidden; overflow-x: hidden; position: relative; -webkit-overflow-scrolling: touch; overflow-y: scroll; } /* Styles for moving the pages */ #horizontalPagesWrapper { display: flex; flex-direction: row; } .pageOpen { width: 100%; max-height: 100%; } .pageClosed { max-width: 0px; max-height: 0px; overflow: hidden; } .certOpenLeft { position: absolute; width: 100%; left: 100%; } .certMoveToFront { width: 100%; left: 0; } .certMoveToSide { position: absolute; max-width: 100%; left: 100%; } /* Page styles*/ @media only screen and (min-width: 769px) { .contentContainer { display: flex; align-items: center; flex-direction: column; width: 100%; } } @media only screen and (max-width: 768px) { .contentContainer { display: flex; align-items: center; flex-direction: column; width: 100%; } }
原JS代码
function ScrollUpAndActivateCertificates() { // Check if page is at the top if (window.scrollY === 0) { document.getElementsByClassName("certificates")[0].classList.remove("pageClosed"); document.getElementsByClassName("certificates")[0].classList.add("certOpenLeft"); scrollRightAndRemoveFrontpage(); } // Scroll to top and restart function else { window.scrollTo({ top: 0, behavior: "smooth" }); setTimeout(ScrollUpAndActivateCertificates, 1000); } } function scrollRightAndRemoveFrontpage() { window.scrollTo({ left: window.innerWidth, behavior: "smooth" }); if (window.scrollX >= window.innerWidth - 100) // Needs leeway for windows scrollbar? { // Disable front page document.getElementsByClassName("frontpage")[0].classList.remove("pageOpen"); document.getElementsByClassName("frontpage")[0].classList.add("pageClosed"); // Set cert as the only page document.getElementsByClassName("certificates")[0].classList.add("certMoveToFront"); document.getElementsByClassName("certificates")[0].classList.remove("certOpenLeft"); } else { setTimeout(scrollRightAndRemoveFrontpage, 1000); } } function ScrollUpAndActivateFrontpage() { if (window.scrollY === 0) { document.getElementsByClassName("frontpage")[0].classList.remove("pageClosed"); document.getElementsByClassName("frontpage")[0].classList.add("pageOpen"); document.getElementsByClassName("certificates")[0].classList.remove("certMoveToFront"); document.getElementsByClassName("certificates")[0].classList.add("certOpenLeft"); // Disabling active styles document.getElementsByClassName("certificates")[0].classList.remove("certMoveToFront"); // Making sure the page is scrolled to the right when other page is activated window.scrollTo({ left: window.innerWidth, behavior: "auto" }); ScrollLeftAndRemoveCertificates(); } else { window.scrollTo({ top: 0, behavior: "smooth" }); setTimeout(ScrollUpAndActivateFrontpage, 1000); } } function ScrollLeftAndRemoveCertificates() { window.scrollTo({ left: 0, behavior: "smooth" }); if (pageXOffset == 0) { document.getElementsByClassName("certificates")[0].classList.add("pageClosed"); document.getElementsByClassName("certificates")[0].classList.remove("certOpenLeft"); } else { setTimeout(ScrollLeftAndRemoveCertificates, 1000); } }
问题根源
body的overflow-x: hidden限制:直接截断了横向滚动空间,脚本无法触发滚动,因为没有可滚动的区域- 绝对定位脱离布局流:
.certOpenLeft用绝对定位脱离了flex容器,导致#horizontalPagesWrapper宽度无法被撑开,没有产生横向滚动的基础 - 滚动判断逻辑不可靠:固定1秒的定时器无法适配移动端平滑滚动的延迟,
scrollX值可能还没达到目标就执行了判断 - 宽度单位不匹配:用
100%作为页面宽度,在flex布局下容易出现计算偏差,尤其是移动端视口变化时
修复方案
1. 调整CSS核心样式
body { background-color: white; font-family: 'Lato'; margin: 0; padding: 0; backface-visibility: hidden; /* 移除overflow-x: hidden,把横向滚动交给容器处理 */ position: relative; -webkit-overflow-scrolling: touch; overflow-y: scroll; } #horizontalPagesWrapper { display: flex; flex-direction: row; width: fit-content; /* 让容器宽度自动适配子元素总宽度 */ overflow-x: auto; /* 开启容器横向滚动 */ -webkit-overflow-scrolling: touch; /* 移动端平滑滚动支持 */ } .pageOpen { width: 100vw; /* 用视口宽度确保页面占满屏幕 */ min-height: 100vh; /* 占满视口高度,避免滚动区域异常 */ } .pageClosed { width: 0; /* 用width替代max-width,确保完全隐藏 */ min-height: 0; overflow: hidden; flex-shrink: 0; /* 防止flex容器压缩元素 */ } .certOpenLeft { /* 移除绝对定位,让页面留在flex容器内 */ width: 100vw; min-height: 100vh; flex-shrink: 0; /* 固定宽度,不被压缩 */ } .certMoveToFront { width: 100vw; min-height: 100vh; }
2. 优化JS逻辑
// 提前缓存DOM元素,减少重复查询 const frontpage = document.querySelector('.frontpage'); const certificates = document.querySelector('.certificates'); const wrapper = document.getElementById('horizontalPagesWrapper'); function ScrollUpAndActivateCertificates() { if (window.scrollY === 0) { certificates.classList.remove('pageClosed'); certificates.classList.add('certOpenLeft'); // 等待DOM更新后执行滚动,用scrollIntoView更可靠 requestAnimationFrame(() => { certificates.scrollIntoView({ behavior: 'smooth', inline: 'start' }); // 根据平滑滚动时长设置延迟,确保滚动完成后再切换状态 setTimeout(() => { frontpage.classList.remove('pageOpen'); frontpage.classList.add('pageClosed'); certificates.classList.add('certMoveToFront'); certificates.classList.remove('certOpenLeft'); }, 1000); }); } else { window.scrollTo({ top: 0, behavior: 'smooth' }); setTimeout(ScrollUpAndActivateCertificates, 1000); } } function ScrollUpAndActivateFrontpage() { if (window.scrollY === 0) { frontpage.classList.remove('pageClosed'); frontpage.classList.add('pageOpen'); certificates.classList.remove('certMoveToFront'); certificates.classList.add('certOpenLeft'); requestAnimationFrame(() => { frontpage.scrollIntoView({ behavior: 'smooth', inline: 'start' }); setTimeout(() => { certificates.classList.add('pageClosed'); certificates.classList.remove('certOpenLeft'); }, 1000); }); } else { window.scrollTo({ top: 0, behavior: 'smooth' }); setTimeout(ScrollUpAndActivateFrontpage, 1000); } }
关键优化点
- 把横向滚动的控制权交给
#horizontalPagesWrapper,避免和body的垂直滚动冲突 - 用
100vw代替100%,确保页面宽度始终匹配视口,解决移动端布局偏差 - 使用
scrollIntoView替代手动设置scrollX,自动适配容器滚动位置,更适配移动端 - 缓存DOM元素,减少重复查询提升性能
- 调整页面高度为
100vh,确保滚动区域完整
内容的提问来源于stack exchange,提问作者mico vihavainen
相关产品推荐
相关产品推荐

