如何使透明div后方的内容不可滚动/保持静态?
解决侧边栏遮罩层后方内容可滚动的问题
问题说明
开发侧边栏时,后方的深色透明遮罩层点击可隐藏侧边栏,但遮罩层透明状态下,用户仍能滚动后方页面内容,需要实现遮罩层显示时,后方内容静态不可滚动。
解决方案
方法1:锁定body全局滚动(最常用)
当侧边栏(含遮罩层)显示时,给body添加样式类锁定滚动,隐藏时移除该类。
修改后的组件代码:
import { useEffect, useState } from 'react'; export default function Sidebar() { const [isOpen, setIsOpen] = useState(true); // 根据业务逻辑控制侧边栏显隐 // 监听侧边栏状态,控制body滚动 useEffect(() => { const body = document.body; if (isOpen) { body.classList.add('no-scroll'); } else { body.classList.remove('no-scroll'); } // 组件卸载时清理样式,避免影响其他页面 return () => body.classList.remove('no-scroll'); }, [isOpen]); // 点击遮罩层关闭侧边栏 const closeSidebar = () => setIsOpen(false); return ( {/* 外层遮罩层,覆盖整个视口 */} <div className={`sidebar-overlay ${isOpen ? 'active' : ''}`} onClick={closeSidebar}> {/* 侧边栏容器,点击内部阻止事件冒泡,避免触发遮罩层的关闭逻辑 */} <div className="sidebar-container" onClick={e => e.stopPropagation()}> <div className="sidebar"> <header>header</header> <ul> <li> <div className="sidebar-item">item</div> </li> </ul> </div> </div> </div> ); }
对应的CSS样式:
/* 遮罩层基础样式 */ .sidebar-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.5); /* 深色透明效果 */ display: none; /* 默认隐藏 */ } /* 遮罩层激活状态 */ .sidebar-overlay.active { display: block; } /* 锁定body滚动的类 */ .no-scroll { overflow: hidden; /* 兼容iOS滚动问题,可选 */ position: fixed; width: 100%; } /* 侧边栏容器样式示例 */ .sidebar-container { position: fixed; right: 0; top: 0; height: 100vh; width: 300px; background-color: #fff; /* 可添加其他样式如阴影、内边距等 */ }
方法2:遮罩层阻止滚动事件传递
如果不需要锁定整个页面滚动,可在遮罩层上监听滚动相关事件,阻止事件传递到后方内容。
修改后的组件代码:
import { useState } from 'react'; export default function Sidebar() { const [isOpen, setIsOpen] = useState(true); const closeSidebar = () => setIsOpen(false); // 阻止滚动事件 const preventScroll = e => e.preventDefault(); return ( <div className={`sidebar-overlay ${isOpen ? 'active' : ''}`} onClick={closeSidebar} onWheel={preventScroll} onTouchMove={preventScroll} > <div className="sidebar-container" onClick={e => e.stopPropagation()}> <div className="sidebar"> <header>header</header> <ul> <li> <div className="sidebar-item">item</div> </li> </ul> </div> </div> </div> ); }
对应的CSS样式:
.sidebar-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.5); display: none; pointer-events: auto; /* 确保遮罩层能接收事件 */ } .sidebar-overlay.active { display: block; } .sidebar-container { position: fixed; right: 0; top: 0; height: 100vh; width: 300px; background-color: #fff; }
关键注意事项
- 方法1是行业通用方案,能彻底解决滚动问题,但必须在组件卸载时清理
no-scroll类,避免影响其他页面的正常滚动。 - 方法2适合局部场景,但要同时处理鼠标滚轮(
wheel)和移动端触摸滚动(touchmove)事件,确保兼容性。 - 遮罩层必须是外层容器,侧边栏内部点击通过
stopPropagation()阻止事件冒泡,避免误触关闭逻辑。
内容的提问来源于stack exchange,提问作者Marc x
相关产品推荐
相关产品推荐

