You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ReactJS与Framer Motion中实现Y轴滚动联动X轴滚动

React + Framer Motion实现滚动联动:Y轴滚动触发X轴横向滚动

核心思路

监听页面垂直滚动进度,将该进度映射为目标横向容器的水平偏移量,借助Framer Motion的useScroll和useTransform钩子实现平滑的滚动联动,复刻目标板块的交互效果。

实现步骤与代码示例

1. 基础组件结构

先搭建页面框架:一个提供垂直滚动空间的父容器,内部包含横向排列的项目列表容器。

import { motion, useScroll, useTransform } from "framer-motion";
import { useRef, useEffect, useState } from "react";
import "./OurWork.css";

const OurWork = () => {
  // 滚动联动逻辑将在此添加
  
  return (
    <section className="our-work-container">
      <motion.div 
        className="horizontal-scroll-content"
        ref={contentRef}
        style={{ x: scrollXOffset }}
      >
        {[1,2,3,4,5,6,7].map((item) => (
          <div key={item} className="work-card">
            <div className="card-content">Project {item}</div>
          </div>
        ))}
      </motion.div>
    </section>
  );
};

export default OurWork;

2. 添加滚动联动逻辑

用Framer Motion的钩子把垂直滚动进度转换成横向容器的X轴偏移:

const OurWork = () => {
  const contentRef = useRef(null);
  const [maxOffset, setMaxOffset] = useState(0);

  // 获取整个页面的垂直滚动进度
  const { scrollYProgress } = useScroll({
    target: document.documentElement,
    offset: ["start start", "end end"]
  });

  // 计算横向内容的最大滚动偏移量(内容总宽度 - 容器可视宽度)
  useEffect(() => {
    const updateMaxOffset = () => {
      if (contentRef.current) {
        const { scrollWidth, clientWidth } = contentRef.current;
        setMaxOffset(scrollWidth - clientWidth);
      }
    };

    updateMaxOffset();
    // 监听窗口 resize,动态更新偏移量
    window.addEventListener("resize", updateMaxOffset);
    return () => window.removeEventListener("resize", updateMaxOffset);
  }, []);

  // 将0-1的滚动进度映射为X轴偏移值:0对应0,1对应-maxOffset
  const scrollXOffset = useTransform(scrollYProgress, [0, 1], [0, -maxOffset]);

  return (
    <section className="our-work-container">
      <motion.div 
        className="horizontal-scroll-content"
        ref={contentRef}
        style={{ x: scrollXOffset }}
      >
        {[1,2,3,4,5,6,7].map((item) => (
          <div key={item} className="work-card">
            <div className="card-content">Project {item}</div>
          </div>
        ))}
      </motion.div>
    </section>
  );
};

3. 关键样式配置(OurWork.css)

确保横向容器正常排列,父容器提供足够垂直滚动空间:

.our-work-container {
  min-height: 200vh; /* 让页面有足够垂直滚动区域 */
  display: flex;
  align-items: center;
  overflow: hidden;
  padding: 4rem 0;
}

.horizontal-scroll-content {
  display: flex;
  gap: 2rem;
  padding: 0 1rem;
  /* 隐藏原生横向滚动条 */
  scrollbar-width: none;
}

.horizontal-scroll-content::-webkit-scrollbar {
  display: none;
}

.work-card {
  width: 350px;
  height: 450px;
  flex-shrink: 0;
  background-color: #f0f0f0;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  font-weight: 500;
}

关键细节说明

  • useScroll的offset参数:["start start", "end end"]定义滚动进度的起止点——当页面顶部与视口顶部对齐时进度为0,页面底部与视口底部对齐时进度为1,确保联动范围覆盖整个垂直滚动过程。
  • 动态偏移量计算:通过监听窗口resize事件,实时更新横向内容的最大偏移量,适配不同屏幕尺寸。
  • 平滑动画:Framer Motion的useTransform会自动处理偏移值的过渡动画,无需额外添加缓动逻辑。

内容的提问来源于stack exchange,提问作者DeadMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 18:45:38