是否有可生成自定义关键帧函数的JavaScript库或方法?
实现关键帧驱动的滚动图片高度动画
直接上可行的实现方案,核心是写一个关键帧插值工具函数,配合滚动事件实时计算即可:
首先定义你的关键帧配置,每个关键帧可以指定对应的缓动函数(没有的话默认线性插值):
// 关键帧配置:按时间点升序排列,time范围0-1,value是目标高度(px),easing是可选的插值函数 const heightKeyframes = [ { time: 0, value: 400 }, { time: 0.5, value: 400 }, { time: 0.75, value: 200, easing: (t) => 1 - Math.pow(1 - t, 3) }, // 指数递减缓动 { time: 0.95, value: 150 }, { time: 1, value: 150 } ];
然后写一个插值计算函数,根据当前滚动进度(0-1)返回对应的高度值:
function getInterpolatedValue(progress, keyframes) { // 处理边界情况:进度小于第一个关键帧或大于最后一个 if (progress <= keyframes[0].time) return keyframes[0].value; if (progress >= keyframes[keyframes.length - 1].time) return keyframes[keyframes.length - 1].value; // 找到当前进度所在的关键帧区间 let prevFrame, nextFrame; for (let i = 0; i < keyframes.length - 1; i++) { prevFrame = keyframes[i]; nextFrame = keyframes[i + 1]; if (progress >= prevFrame.time && progress <= nextFrame.time) break; } // 计算区间内的相对进度(0-1) const t = (progress - prevFrame.time) / (nextFrame.time - prevFrame.time); // 应用缓动函数,默认线性 const easedT = nextFrame.easing ? nextFrame.easing(t) : t; // 计算插值后的最终值 return prevFrame.value + (nextFrame.value - prevFrame.value) * easedT; }
接下来绑定滚动事件,实时计算滚动进度并更新图片高度:
const targetImg = document.getElementById('animated-img'); function updateImgHeight() { // 计算当前滚动进度:0(顶部)到1(底部) const scrollTop = window.scrollY; const totalScrollable = document.documentElement.scrollHeight - window.innerHeight; const scrollProgress = totalScrollable > 0 ? scrollTop / totalScrollable : 0; // 获取插值后的高度 const currentHeight = getInterpolatedValue(scrollProgress, heightKeyframes); // 应用到图片 targetImg.style.height = `${currentHeight}px`; } // 初始化执行一次,避免初始状态错误 updateImgHeight(); // 绑定滚动事件 window.addEventListener('scroll', updateImgHeight); // 窗口 resize 时也更新,避免滚动进度计算错误 window.addEventListener('resize', updateImgHeight);
对应的HTML结构示例:
<img id="animated-img" src="your-image.jpg" style="width: 100%; object-fit: cover;" />
关键说明:
- 关键帧必须按时间点升序排列,否则区间查找会出错
- 缓动函数接收一个0-1的参数
t,返回0-1的处理后值,你可以自定义各种曲线:- 指数递减:
(t) => 1 - Math.pow(1 - t, 3) - 线性:
(t) => t(默认) - 二次缓入:
(t) => t * t - 你甚至可以写自定义的非线性逻辑,只要输出在0-1范围内即可
- 指数递减:
- 滚动进度计算考虑了窗口resize的情况,避免布局变化导致进度错误
内容的提问来源于stack exchange,提问作者EricHier
相关产品推荐
相关产品推荐

