如何在容器滚动时动态更新两侧渐变阴影的显示状态?
横向滚动容器渐变阴影实时更新方案
问题背景
我有一个包含5个盒子的display: flex横向滚动容器(类名boxes),可通过左右按钮控制滚动。需求是:
- 容器左右两侧显示白色渐变阴影
- 滚动到最左侧时,仅显示右侧阴影
- 滚动到最右侧时,仅显示左侧阴影
- 其余状态显示两侧阴影,且阴影需随滚动实时更新
但当前阴影固定在初始位置,滚动时不会随容器移动,甚至会出现在容器中间位置,请问该如何实现阴影的实时更新?
原方案问题分析
原代码用容器的::after伪元素做遮罩,但伪元素是绝对定位在容器的可视范围内,不会跟随滚动的内容移动,导致遮罩位置和滚动状态完全脱节。另外JS里硬编码了最大滚动值1206,一旦内容长度或容器尺寸变化,这个值就会失效,兼容性极差。
优化解决方案
核心思路
- 把单一遮罩拆成左右两个独立的遮罩元素,固定在容器的左右边缘,确保视觉上始终贴合视口两侧
- 通过滚动事件动态判断滚动状态,控制遮罩的显示/隐藏,而非修改渐变参数
- 动态计算最大滚动值,彻底摆脱硬编码数值的限制
完整实现代码
HTML(新增遮罩元素)
<div class="boxes"> <!-- 原有盒子内容 --> <div class="box">Box 1</div> <div class="box">Box 2</div> <div class="box">Box 3</div> <div class="box">Box 4</div> <div class="box">Box 5</div> <!-- 新增左右渐变遮罩 --> <div class="shadow-overlay shadow-left"></div> <div class="shadow-overlay shadow-right"></div> </div>
CSS(SCSS)
.boxes { display: flex; overflow-x: scroll; -ms-overflow-style: none; scrollbar-width: none; scroll-behavior: smooth; position: relative; padding: 0; &::-webkit-scrollbar { display: none; } .shadow-overlay { position: absolute; top: 0; bottom: 0; width: 60px; /* 遮罩宽度可按需调整 */ z-index: 1; pointer-events: none; /* 不干扰容器内的点击交互 */ opacity: 0; transition: opacity 0.2s ease; /* 平滑过渡效果 */ } .shadow-left { left: 0; background: linear-gradient(90deg, #fff, transparent); } .shadow-right { right: 0; background: linear-gradient(-90deg, #fff, transparent); } }
JavaScript
const boxesView = document.querySelector('.boxes'); const shadowLeft = boxesView.querySelector('.shadow-left'); const shadowRight = boxesView.querySelector('.shadow-right'); // 初始化遮罩状态 updateShadows(); // 滚动时更新遮罩 boxesView.addEventListener('scroll', updateShadows); // 窗口尺寸变化时重新计算(适配响应式场景) window.addEventListener('resize', updateShadows); function updateShadows() { // 动态计算最大滚动值:内容总宽度 - 容器可视宽度 const maxScrollLeft = boxesView.scrollWidth - boxesView.clientWidth; if (boxesView.scrollLeft <= 0) { // 滚动到最左侧:隐藏左遮罩,显示右遮罩 shadowLeft.style.opacity = '0'; shadowRight.style.opacity = '1'; } else if (boxesView.scrollLeft >= maxScrollLeft - 1) { // 滚动到最右侧:显示左遮罩,隐藏右遮罩(减1兼容滚动精度误差) shadowLeft.style.opacity = '1'; shadowRight.style.opacity = '0'; } else { // 中间状态:显示两侧遮罩 shadowLeft.style.opacity = '1'; shadowRight.style.opacity = '1'; } }
方案优势
- 遮罩固定在容器边缘,不会随内容滚动偏移,视觉效果始终符合预期
- 通过
opacity控制显示状态,逻辑简洁且性能开销低 - 动态计算最大滚动值,适配任意内容长度和容器尺寸
- 支持窗口尺寸变化时自动更新,兼容响应式场景
内容的提问来源于stack exchange,提问作者tices
相关产品推荐
相关产品推荐

