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

如何用Framer Motion实现类似GSAP的元素固定(Pin)效果?

用Framer Motion实现GSAP式元素固定(Pin)效果

完全可以用Framer Motion实现类似GSAP的元素固定(Pin)效果,核心是通过useScroll和useTransform钩子结合滚动位置控制元素的定位与位移,下面是具体实现方案:

基础实现思路

Pin效果的本质是:当滚动到指定位置时,元素固定在视口的某个位置;当滚动过预设的固定区域后,元素跟随滚动流继续移动。Framer Motion的滚动相关钩子可以精准捕捉滚动状态,再映射为元素的样式变化。

代码示例

1. 基础固定效果

import { motion, useScroll, useTransform } from "framer-motion";

export default function PinElement() {
  // 获取全局滚动的垂直像素值
  const { scrollY } = useScroll();
  
  // 定义固定区间:滚动到200px时开始固定,滚动到800px时结束固定
  const pinStart = 200;
  const pinEnd = 800;
  
  // 将滚动位置映射为0-1的进度值,用于计算元素位移
  const pinProgress = useTransform(scrollY, [pinStart, pinEnd], [0, 1]);
  // 控制元素y轴位移:固定区间内保持0(固定状态),超出后随滚动偏移
  const elementY = useTransform(pinProgress, [0, 1], [0, pinEnd - pinStart]);

  return (
    <div style={{ height: "2000px", padding: "0 20px" }}>
      <div style={{ height: "200px" }}>向下滚动查看固定效果</div>
      
      <motion.div
        style={{
          position: "fixed",
          top: "20px",
          width: "200px",
          height: "200px",
          backgroundColor: "#2d3748",
          color: "#fff",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          y: elementY
        }}
        transition={{ ease: "easeInOut" }}
      >
        固定元素
      </motion.div>
      
      <div style={{ height: "800px", marginTop: "240px" }}>固定区域占位内容</div>
    </div>
  );
}

2. 结合视口检测的智能固定

如果需要元素进入视口后才触发固定,可以搭配useInView钩子实现:

import { motion, useScroll, useTransform, useInView } from "framer-motion";
import { useRef } from "react";

export default function SmartPinElement() {
  const pinRef = useRef(null);
  // 检测元素是否在视口内(非一次性检测)
  const isElementInView = useInView(pinRef, { once: false });
  const { scrollY } = useScroll();
  
  // 动态计算固定区间(可根据元素位置调整)
  const pinStart = 300;
  const pinEnd = pinStart + 600;
  const elementY = useTransform(scrollY, [pinStart, pinEnd], [0, pinEnd - pinStart]);

  return (
    <div style={{ height: "2000px" }}>
      <div style={{ height: "300px" }}></div>
      
      <motion.div
        ref={pinRef}
        style={{
          // 视口内时切换为固定定位,否则保持相对定位
          position: isElementInView ? "fixed" : "relative",
          top: "20px",
          left: "20px",
          width: "200px",
          height: "200px",
          backgroundColor: "#2d3748",
          color: "#fff",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          // 仅在视口内时应用位移变换
          y: isElementInView ? elementY : 0
        }}
        transition={{ ease: "easeInOut" }}
      >
        智能固定元素
      </motion.div>
      
      <div style={{ height: "600px", marginTop: "240px" }}></div>
    </div>
  );
}

关键逻辑说明

  • useScroll:获取滚动的核心数据(如scrollY垂直滚动像素值、scrollYProgress滚动进度)
  • useTransform:将滚动数据映射为元素的样式属性(这里是y轴位移),实现滚动与元素状态的关联
  • 定位切换:通过position: fixed实现固定,超出固定区间后利用y轴位移让元素跟随滚动流移动

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:35:26