如何实现特定div的滚动行为切换:垂直转水平后恢复默认?
多段垂直转水平滚动Section的实现方案
一、成熟库推荐
- ScrollTrigger(GSAP生态):这是实现滚动交互的主流工具,原生支持滚动位置监听,能精准触发垂直到水平的滚动切换逻辑,而且天生支持多段独立的滚动区块,每个section可单独配置触发条件和滚动行为,不需要额外做太多兼容性处理。
- Locomotive Scroll:轻量级自定义滚动库,支持通过监听滚动位置,结合CSS transform实现垂直转水平的滚动切换,对多区块场景的兼容性很好,配置也相对灵活。
二、原生JS自行实现思路
如果不想依赖第三方库,核心是通过监听页面滚动事件,控制目标section的滚动行为,步骤如下:
1. DOM结构准备
给每个需要切换滚动的section添加统一类名(比如horizontal-scroll-section),内部嵌套一个容器承载水平内容:
<section class="horizontal-scroll-section"> <div class="scroll-inner"> <div class="scroll-item">区块内容1</div> <div class="scroll-item">区块内容2</div> <!-- 更多水平内容 --> </div> </section>
2. 基础样式配置
设置section固定高度,内部容器自适应宽度以容纳所有水平内容,默认保持垂直滚动:
.horizontal-scroll-section { height: 100vh; /* 占满视口高度,明确触发边界 */ overflow: hidden; position: relative; } .scroll-inner { display: flex; width: max-content; height: 100%; } .scroll-item { width: 100vw; height: 100%; }
3. 核心滚动逻辑
- 监听页面滚动,判断每个section的位置是否进入触发范围;
- 当section顶部到达视口顶部且未滚到右侧尽头时,拦截默认垂直滚动,将垂直滚动量转化为内部容器的水平偏移;
- 滚到右侧尽头或离开section范围后,恢复默认垂直滚动。
核心代码示例:
const horizontalSections = document.querySelectorAll('.horizontal-scroll-section'); let isScrollLocked = false; // 节流函数优化性能 function throttle(func, delay) { let lastCall = 0; return function(...args) { const now = Date.now(); if (now - lastCall >= delay) { lastCall = now; return func(...args); } }; } const handleScroll = throttle((e) => { horizontalSections.forEach(section => { const rect = section.getBoundingClientRect(); const innerContainer = section.querySelector('.scroll-inner'); const maxHorizontalScroll = innerContainer.scrollWidth - section.clientWidth; const sectionOffsetTop = section.offsetTop; // 进入触发范围:section在视口内,且未滚到右侧尽头 if (rect.top <= 0 && rect.bottom > 0 && innerContainer.scrollLeft < maxHorizontalScroll) { isScrollLocked = true; e.preventDefault(); // 将垂直滚动距离转为水平偏移 const verticalScrollAmount = window.scrollY - sectionOffsetTop; innerContainer.scrollLeft = verticalScrollAmount; } // 滚到右侧尽头,解锁垂直滚动 else if (innerContainer.scrollLeft >= maxHorizontalScroll) { isScrollLocked = false; } // 离开section范围,重置状态 else { isScrollLocked = false; innerContainer.scrollLeft = 0; // 可选:离开后重置水平位置 } }); }, 16); window.addEventListener('scroll', handleScroll); // 处理触摸滚动 window.addEventListener('touchmove', (e) => { if (isScrollLocked) e.preventDefault(); }, { passive: false });
4. 关键优化点
- 用节流函数减少滚动事件触发频率,避免性能损耗;
- 处理触摸滚动事件,确保移动端行为一致;
- 给每个section独立维护状态,避免多区块之间的逻辑冲突;
- 可添加过渡动画,让滚动切换更平滑(比如给
scroll-inner的scrollLeft添加transition)。
内容的提问来源于stack exchange,提问作者ibi0tux
相关产品推荐
相关产品推荐

