如何用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
相关产品推荐
相关产品推荐

