如何实现滚动容器内容末尾的Pull effect(拉动效果)?
移动端水平滚动容器末尾拉动反馈实现方案
纯CSS无法实现这种跟随触摸拖动的动态反馈效果,需要结合JavaScript监听触摸事件来实现,以下是完整的实现方案:
实现思路
- 监听容器的触摸开始、滑动、结束事件
- 判断滚动是否到达容器末尾
- 拖动过程中动态调整内容位置模拟拉动效果
- 松手后通过过渡动画让内容回弹至原位置
完整代码示例
HTML结构
<div class="horizontal-scroll-container"> <div class="scroll-content"> <!-- 自定义滚动内容 --> <div class="item">内容1</div> <div class="item">内容2</div> <div class="item">内容3</div> <div class="item">内容4</div> <div class="item">内容5</div> <div class="item">内容6</div> <div class="item">内容7</div> <div class="item">内容8</div> </div> </div>
CSS样式
.horizontal-scroll-container { overflow-x: auto; overflow-y: hidden; touch-action: pan-x; /* 优化移动端触摸滚动行为 */ width: 100%; position: relative; } .scroll-content { display: flex; gap: 16px; padding: 12px; transition: transform 0.3s ease-out; /* 回弹动画 */ will-change: transform; /* 提前告知浏览器做性能优化 */ } .item { width: 150px; height: 200px; background: #eee; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; /* 防止内容被压缩 */ } /* 可选:隐藏原生滚动条 */ .horizontal-scroll-container::-webkit-scrollbar { display: none; }
JavaScript逻辑
const container = document.querySelector('.horizontal-scroll-container'); const content = document.querySelector('.scroll-content'); let isDragging = false; let startX = 0; let startScrollLeft = 0; let pullDistance = 0; const maxPull = 40; // 限制最大拉动距离,避免过度拖动 // 触摸开始事件 container.addEventListener('touchstart', (e) => { isDragging = true; startX = e.touches[0].clientX; startScrollLeft = container.scrollLeft; content.style.transition = 'none'; // 拖动时关闭过渡,保证流畅 }); // 触摸滑动事件 container.addEventListener('touchmove', (e) => { if (!isDragging) return; const currentX = e.touches[0].clientX; const deltaX = currentX - startX; const isAtEnd = container.scrollLeft >= (container.scrollWidth - container.clientWidth); // 仅当已滚动到末尾且向右拖动时,应用拉动效果 if (isAtEnd && deltaX > 0) { pullDistance = Math.min(deltaX / 3, maxPull); // 缩小拉动幅度,效果更自然 content.style.transform = `translateX(${pullDistance}px)`; } else if (!isAtEnd) { // 未到末尾时恢复正常状态 pullDistance = 0; content.style.transform = 'translateX(0)'; } }); // 触摸结束事件 container.addEventListener('touchend', () => { isDragging = false; // 开启过渡动画,让内容回弹 content.style.transition = 'transform 0.3s ease-out'; content.style.transform = 'translateX(0)'; }); // 处理触摸中断情况(如来电) container.addEventListener('touchcancel', () => { isDragging = false; content.style.transition = 'transform 0.3s ease-out'; content.style.transform = 'translateX(0)'; });
关键说明
touch-action: pan-x:指定浏览器仅允许水平触摸滚动,避免垂直触摸行为干扰- 拖动时关闭过渡动画,松手后重新开启,保证拉动流畅且回弹自然
- 对拉动幅度做了缩小处理,让反馈效果更贴近Instagram、YouTube的体验
- 限制最大拉动距离,防止过度拖动影响页面体验
内容的提问来源于stack exchange,提问作者Eryk Wróbel
相关产品推荐
相关产品推荐

