
本文详解如何使用 Framer Motion 的 useScroll 与 useTransform 实现元素在视口中心时完全不透明、上下滚动时对称衰减的「钟形」淡入淡出效果,关键在于正确配置 offset 参数与映射区间。
本文详解如何使用 framer motion 的 `usescroll` 与 `usetransform` 实现元素在视口中心时完全不透明、上下滚动时对称衰减的「钟形」淡入淡出效果,关键在于正确配置 `offset` 参数与映射区间。
在 Framer Motion 中,实现“滚动到元素中心时完全显示,向上或向下偏移时渐隐”的效果,核心并非修改 useTransform 的映射逻辑([0, 0.5, 1] → [0, 1, 0] 本身已正确),而在于让 scrollYProgress 的取值范围真正以元素中心为对称轴。默认 ["start end", "end end"] 的 offset 配置将 scrollYProgress = 0 绑定到“元素顶部抵达视口底部”,scrollYProgress = 1 绑定到“元素底部抵达视口底部”——这导致进度值仅随向下滚动单向增长,无法反映元素相对于视口中心的双向偏移。
✅ 正确解法:将 offset 改为 ["start center", "end center"]。
这一配置定义了两个关键交点:
-
scrollYProgress = 0:当目标元素顶部与视口中心线对齐时; -
scrollYProgress = 1:当目标元素底部与视口中心线对齐时。
此时,scrollYProgress = 0.5 恰好对应元素整体垂直居中于视口中心线(即元素几何中心与视口中心重合),完美满足需求。
以下是修正后的完整可运行代码:
import { useRef } from 'react';
import { motion, useScroll, useTransform } from 'framer-motion';
export default function ScrollFadeSection() {
const ref = useRef<htmldivelement>(null);
// ✅ 关键修正:使用 ["start center", "end center"] 实现中心对称滚动进度
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start center", "end center"], // ← 核心改动
});
// 将 [0, 0.5, 1] 映射为 [0, 1, 0],形成钟形曲线
const opacity = useTransform(scrollYProgress, [0, 0.5, 1], [0, 1, 0]);
return (
<div ref="{ref}" classname="flex flex-col items-center justify-center border border-blue-600 text-7xl h-screen">
<motion.div style="{{" opacity classname="text-center">
hello
</motion.div>
</div>
);
}</htmldivelement>
? 为什么这样有效?scrollYProgress 是一个归一化信号(0→1),它线性描述了目标元素在指定 offset 区间内的相对位移。["start center", "end center"] 构建了一个以“元素中心居中”为峰值的滑动窗口:当用户滚动使元素从视口上方进入,到完全居中,再到移出视口下方,scrollYProgress 从 0 平滑增至 1,useTransform 的三段映射便自然生成对称的淡入→全显→淡出效果。
⚠️ 注意事项:
- 若需更宽泛的淡入/淡出区间(例如提前开始淡入、延迟完全消失),可调整
offset为["start 80%", "end 20%"]等自定义值,或扩展useTransform的输入数组(如[0, 0.3, 0.5, 0.7, 1])实现更精细控制; - 确保目标元素有明确高度(如本例中的
h-screen),否则start/end计算可能失准; - 在复杂布局中,可结合
rootMargin(通过useScroll的container选项间接控制)微调触发边界。
掌握 offset 的语义化配置,是解锁 Framer Motion 滚动动画精确性的第一把钥匙——它让动画真正“理解”你的设计意图,而非被动响应滚动像素。










