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

使用Framer Motion实现滚动进度条效果失败,求排查问题

滚动进度条不生效的问题排查与修复

问题描述

想要实现滚动时进度条宽度随滚动进度增加的效果,使用Framer Motion的useScroll和useSpring Hook但未成功。原代码如下:

组件代码

import { Grid, Stack, Typography, styled } from "@mui/material";
import { motion, useScroll, useSpring, useTransform } from "framer-motion";
import { useEffect, useRef } from "react";
const ProgressLineStyled = styled("div")(({ theme }) => ({
  height: "10px",
  borderRadius: "10px",
  backgroundColor: "white",
}));
function Projects() {
  const ref = useRef(null);
  const { scrollYProgress } = useScroll({
    container: ref,
    offset: ["end end", "start start"],
  });
  const scalesX = useSpring(scrollYProgress, { damping: 30, stiffness: 100 });
  return (
    <Grid
      sx={{ pt: 12 }}
      height="100%"
      position="relative"
      component={motion.div}
      border="12px solid"
      container
    >
      <Grid
        component={motion.div}
        display="flex"
        flexDirection="column"
        item
        xs={11}
        ref={ref}
      >
        <Stack
          component={motion.div}
          direction="column"
          justifyContent="center"
          alignItems="center"
          position="sticky"
          top="50px"
          left="0%"
          gap={2}
        >
          <Typography component={motion.div} color="orange" variant="h4">
            Projects
          </Typography>
          <ProgressLineStyled
            component={motion.div}
            style={{ scaleX: scalesX }}
          ></ProgressLineStyled>
        </Stack>
        {Array(5)
          .fill(null)
          .map((e, i) => {
            return (
              <section className="section">
                <span>work {i}</span>
              </section>
            );
          })}
      </Grid>
    </Grid>
  );
}

export default Projects;

section标签样式

.section{
        height:100vh;
        scroll-snap-align: center;
    }

错误原因分析

  • 滚动容器未配置可滚动属性:绑定ref的Grid容器没有设置固定高度和overflow-y: auto,导致浏览器无法识别它为滚动容器,useScroll无法捕获滚动事件。
  • scaleX变换原点错误:默认情况下scaleX的变换原点是元素中心,进度条会从中间向两侧扩展,不符合"从左到右填充"的预期效果。
  • useScroll的offset参数逻辑反了:["end end", "start start"]表示当容器底部与视口底部对齐时进度为0,容器顶部与视口顶部对齐时进度为1,和"滚动向下时进度增加"的需求刚好相反。

修复后的代码

组件代码

import { Grid, Stack, Typography, styled } from "@mui/material";
import { motion, useScroll, useSpring } from "framer-motion";
import { useRef } from "react";

const ProgressLineStyled = styled("div")(({ theme }) => ({
  height: "10px",
  borderRadius: "10px",
  backgroundColor: "white",
  // 设置变换原点为左侧
  transformOrigin: "left center",
}));

function Projects() {
  const ref = useRef(null);
  const { scrollYProgress } = useScroll({
    container: ref,
    // 修正offset:滚动开始时进度0,滚动结束时进度1
    offset: ["start start", "end end"],
  });
  const scalesX = useSpring(scrollYProgress, { damping: 30, stiffness: 100 });

  return (
    <Grid
      sx={{ pt: 12, height: "100vh" }} // 给外层容器设置全屏高度
      position="relative"
      component={motion.div}
      border="12px solid"
      container
    >
      <Grid
        component={motion.div}
        display="flex"
        flexDirection="column"
        item
        xs={11}
        ref={ref}
        sx={{
          height: "100%", // 给滚动容器设置固定高度
          overflowY: "auto", // 开启垂直滚动
        }}
      >
        <Stack
          component={motion.div}
          direction="column"
          justifyContent="center"
          alignItems="center"
          position="sticky"
          top="50px"
          left="0%"
          gap={2}
          sx={{ zIndex: 1 }} // 确保进度条在内容上方
        >
          <Typography component={motion.div} color="orange" variant="h4">
            Projects
          </Typography>
          <ProgressLineStyled
            component={motion.div}
            style={{ scaleX: scalesX }}
          ></ProgressLineStyled>
        </Stack>
        {Array(5)
          .fill(null)
          .map((e, i) => {
            return (
              <section className="section" key={i}> {/* 添加key避免警告 */}
                <span>work {i}</span>
              </section>
            );
          })}
      </Grid>
    </Grid>
  );
}

export default Projects;

保持原section样式不变

.section{
    height:100vh;
    scroll-snap-align: center;
}

关键修改点说明

  1. 给外层Grid设置height: "100vh",给滚动容器(绑定ref的Grid)设置height: "100%"和overflowY: "auto",确保它成为可滚动容器。
  2. 在ProgressLineStyled中添加transformOrigin: "left center",让进度条从左侧开始缩放。
  3. 将useScroll的offset改为["start start", "end end"],使滚动从顶部到底部时进度从0到1递增。
  4. 给循环渲染的section添加key属性,消除React警告。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 02:45:35