移动端如何禁止页面主体滚动但允许导航菜单滚动?
完美解决Off-Canvas导航的滚动问题
嘿,我懂你这个痛点!之前我也踩过移动端Safari下overflow:hidden不起作用、用position:fixed导致页面跳回顶部的坑,给你一套靠谱的解决方案:
核心思路
- 不单纯依赖
overflow:hidden(移动端Safari对body的这个属性支持有bug),而是通过记录滚动偏移+固定body位置锁住主体内容,同时避免页面回顶。 - 给导航菜单设置独立的滚动容器,确保菜单内容超出可视区时能正常滚动,不影响主体。
修改后的完整代码
JavaScript 部分
$(function() { let scrollPosition; // 存储当前滚动位置,用于恢复 $('.menu-toggle').click(function() { $('body').toggleClass('menu-open'); if ($('body').hasClass('menu-open')) { // 打开菜单时:记录滚动位置,固定body在当前位置 scrollPosition = window.scrollY; $('body').css('top', -scrollPosition + 'px'); } else { // 关闭菜单时:清除固定样式,恢复之前的滚动位置 $('body').css('top', ''); window.scrollTo(0, scrollPosition); } }); });
CSS 部分
/* 同时给html和body加样式,解决移动端Safari的overflow失效问题 */ html.menu-open, body.menu-open { overflow: hidden; position: fixed; width: 100%; /* 防止fixed后body宽度收缩 */ } .menu-toggle { font-size:40px; cursor:pointer; position: relative; z-index: 100; /* 确保按钮不会被导航遮挡 */ } nav { background:#fff; width:100%; position:absolute; left:-100%; top: 0; height: 100vh; /* 占满整个视口高度 */ max-height: 100vh; overflow-y: auto; /* 菜单内容超出时允许滚动 */ z-index: 90; transition: left 0.3s ease; /* 添加入场过渡动画,更丝滑 */ } .menu-open nav { left:0; } nav ul { margin:0; padding:0; list-style-type:none; } nav ul li { padding:20px 0 20px 10px; border-bottom: 1px solid #eee; /* 加分割线,提升菜单可读性 */ } .body-content { padding: 1rem; }
HTML 部分
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <html> <body> <header> <span class="menu-toggle">=</span> <nav> <ul> <li>Link 1</li> <li>Link 2</li> <li>Link 3</li> <li>Link 4</li> <li>Link 5</li> <li>Link 6</li> <li>Link 7</li> <li>Link 8</li> <li>Link 9</li> <li>Link 10</li> <!-- 多添加几项,方便测试菜单滚动效果 --> <li>Link 11</li> <li>Link 12</li> <li>Link 13</li> <li>Link 14</li> <li>Link 15</li> </ul> </nav> </header> <div class="body-content"> <!-- 你的长内容保持不变 --> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ac magna sollicitudin, tincidunt nisl sed, eleifend diam. Maecenas venenatis semper mauris. In faucibus congue sapien, ultrices efficitur ante pulvinar id. Duis eget egestas sem. Nullam tincidunt purus ut molestie dignissim. Nunc dictum elit arcu. Curabitur vitae magna tortor. Proin lacinia, nisi sit amet gravida pellentesque, orci neque tempor nunc, sit amet lobortis magna nulla id lorem. Etiam suscipit massa ut diam sollicitudin fringilla ac ac mauris. Vestibulum pretium semper urna. Nulla risus nibh, sollicitudin eget volutpat sit amet, fermentum non enim. Praesent gravida metus in leo pharetra congue. Maecenas augue purus, malesuada tempor venenatis at, maximus at elit. Phasellus ipsum nunc, posuere eu metus in, mattis imperdiet sem. Duis non ultrices mi. Mauris nibh ex, varius vel ipsum vel, fermentum semper tellus. Integer fringilla fringilla pharetra. Vivamus eleifend rhoncus mi at iaculis. Proin suscipit lorem justo. Nulla mauris libero, dapibus a augue et, varius mollis nulla. Etiam iaculis convallis quam. Nulla semper urna vel turpis blandit, in fermentum nunc lobortis. Ut varius dui ac enim fringilla condimentum. Vivamus in condimentum leo. In ullamcorper lacus quam, elementum dictum elit scelerisque non. Pellentesque commodo augue imperdiet, consequat ipsum ut, ultrices libero. Sed non suscipit nisl. Nam tristique vel ante in condimentum. Morbi et sem pharetra, lacinia eros id, pulvinar enim. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse elementum ipsum ac scelerisque hendrerit. Ut tellus eros, aliquet sit amet aliquam et, rhoncus a eros. Donec ut felis ex. Maecenas lobortis risus lacus, vitae vestibulum magna malesuada sit amet. Integer et magna pharetra, egestas lacus non, pretium nisl. Aenean malesuada urna et neque tincidunt tincidunt. In orci ligula, efficitur ut sagittis eget, vestibulum a leo. Phasellus convallis risus et elit sodales, vel sollicitudin arcu elementum. Nulla pretium orci sed aliquet feugiat. Fusce consequat pretium aliquet. Pellentesque dapibus placerat euismod. Aenean eget orci eget enim vestibulum interdum. Donec non enim vel lorem dapibus rhoncus sit amet vel risus. Nulla venenatis egestas mauris, et congue lectus. Etiam ac tristique risus. Aliquam quis pretium nunc. Sed blandit hendrerit lacus, sit amet posuere velit sodales in. Praesent dapibus viverra turpis. Nam auctor volutpat urna, luctus venenatis nulla venenatis eu. Quisque quis purus vitae lorem blandit elementum a dapibus enim. Donec commodo lectus nec ante pulvinar fermentum. Etiam sodales ex sit amet dolor finibus suscipit. Maecenas luctus placerat congue. Morbi eget viverra lacus. Vivamus ultricies augue at tincidunt luctus. Maecenas vel pretium purus, in egestas nisi. </div> </body> </html>
关键改动说明
滚动位置的保存与恢复:
- 打开菜单时用
window.scrollY获取当前滚动距离,通过body.style.top = -scrollPosition配合position:fixed,让页面固定在当前位置,不会跳回顶部。 - 关闭菜单时清除固定样式,用
window.scrollTo精准恢复之前的滚动位置。
- 打开菜单时用
移动端Safari兼容处理:
- 同时给
html和body添加menu-open类并设置overflow:hidden,解决移动端Safari单独给body设置该属性无效的问题。
- 同时给
菜单独立滚动设置:
- 给导航设置
height:100vh和overflow-y:auto,确保菜单内容超出视口时可以独立滚动,完全不影响主体内容的锁定效果。
- 给导航设置
细节体验优化:
- 给导航添加入场过渡动画,让菜单滑入滑出更流畅;给菜单列表项加分割线提升可读性;给菜单按钮设置更高的
z-index,确保不会被导航遮挡。
- 给导航添加入场过渡动画,让菜单滑入滑出更流畅;给菜单列表项加分割线提升可读性;给菜单按钮设置更高的
内容的提问来源于stack exchange,提问作者user13286
相关产品推荐
相关产品推荐

