
本文详解如何通过 css 和 javascript 实现类似 emily garthwaite 作品集网站的“垂直滚动触发水平滚动”交互效果,适用于 portfolio 等创意型网站,兼容现代浏览器并适配 webflow 等可视化建站平台。
本文详解如何通过 css 和 javascript 实现类似 emily garthwaite 作品集网站的“垂直滚动触发水平滚动”交互效果,适用于 portfolio 等创意型网站,兼容现代浏览器并适配 webflow 等可视化建站平台。
实现“鼠标滚轮向下滚动 → 页面内容水平滑动”的效果,并非单纯依赖 overflow-x: auto,而是需主动拦截原生垂直滚动行为,将其映射为容器的水平位移(scrollLeft)。核心原理是:禁用默认垂直滚动,监听 wheel 事件,根据 deltaY 动态更新目标容器的 scrollLeft 值。
✅ 基础 HTML 结构
确保内容容器具有明确的尺寸约束和横向可滚动空间:
<div class="horizontal-scroller" id="scroller">
<div class="content-row">
<section class="panel">项目一</section><section class="panel">项目二</section><section class="panel">项目三</section><section class="panel">项目四</section>
</div>
</div>
✅ 关键 CSS 设置
.horizontal-scroller {
width: 100vw;
height: 100vh; /* 必须显式设置高度(如 100vh 或固定 px) */
overflow: hidden; /* 隐藏原生滚动条,避免双滚动冲突 */
scroll-behavior: auto; /* 禁用平滑滚动,保证 JS 控制精度 */
}
.content-row {
display: flex;
width: max-content; /* 让子项自然排列,不换行 */
height: 100%;
}
.panel {
min-width: 100vw; /* 每个面板占满视口宽度 */
height: 100%;
flex-shrink: 0;
}
✅ JavaScript 控制逻辑(推荐使用)
const scroller = document.getElementById('scroller');
let isScrolling = false;
scroller.addEventListener('wheel', (e) => {
e.preventDefault(); // 关键:阻止默认垂直滚动
// 将 deltaY(垂直滚动量)映射为 scrollLeft 增量(向右/左滚动)
const scrollAmount = e.deltaY * 1.5; // 系数可调,控制灵敏度
scroller.scrollLeft += scrollAmount;
});
// 可选:添加防抖与边界限制(防止过度滚动)
scroller.addEventListener('scroll', () => {
const maxScroll = scroller.scrollWidth - scroller.clientWidth;
if (scroller.scrollLeft maxScroll) scroller.scrollLeft = maxScroll;
});
⚠️ 注意事项与常见问题
- 高度必须显式声明:height: 100vh 或固定像素值(如 height: 989px),否则 overflow: hidden 无效,且 scrollLeft 计算失准;
- Webflow 用户特别提示:Webflow 默认禁用自定义 JS 执行或覆盖滚动行为,需在「Custom Code」区域插入脚本,并确保 无 overflow-y: scroll 冲突样式;建议将 .horizontal-scroller 设为 position: fixed 并置于最顶层;
- 移动端适配:wheel 事件不触发触屏滑动,需额外监听 touchmove 并模拟位移(可结合 gesturestart 判断方向);
- 性能优化:高频 wheel 事件建议使用 requestAnimationFrame 节流,避免卡顿;
- 无障碍考量:该交互会绕过原生滚动语义,务必为键盘用户保留 Tab 导航与 ArrowLeft/Right 键控制逻辑。
这种“垂直驱动水平”的滚动模式本质是滚动行为重定向,而非 CSS 自动能力。它赋予设计师更强的叙事控制力,但也要求开发者精确管理滚动状态与边界条件。调试时,优先检查 scrollWidth 与 clientWidth 是否合理、preventDefault() 是否生效,以及父容器是否意外截断了事件冒泡。











