如何为sticky定位元素实现滚动触发的方向化旋转动画
Sticky元素滚动联动旋转动画实现方案
核心逻辑
直接通过JavaScript跟踪滚动状态,将滚动方向、速度与元素旋转角度绑定:
- 初始状态旋转角度为0,仅当元素处于
position: sticky生效区间时触发动画 - 滚动向下时角度递增至900deg,向上时角度递减,超出粘性区间自动重置为0
- 用滚动帧之间的位置差值计算滚动速度,动态调整角度变化速率,实现动画速度与滚动同步
完整代码实现
HTML结构
<div class="scroll-container"> <div class="content-block">向下滚动触发动画</div> <div class="sticky-element">Sticky Box</div> <div class="content-block">向上滚动反向动画</div> </div>
CSS样式
.scroll-container { min-height: 200vh; padding: 50px 0; } .content-block { height: 100vh; background-color: #f5f5f5; display: flex; align-items: center; justify-content: center; font-size: 2rem; } .sticky-element { position: sticky; top: 20px; width: 160px; height: 160px; background-color: #2196f3; color: white; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; /* 基础过渡保证角度变化平滑 */ transition: transform 0.08s ease-out; }
JavaScript逻辑
const stickyEl = document.querySelector('.sticky-element'); const scrollContainer = document.querySelector('.scroll-container'); let lastScrollPos = window.pageYOffset; let currentRotation = 0; const maxRotation = 900; // 目标旋转角度 let stickyRange = { start: 0, end: 0 }; // 计算sticky元素的有效滚动区间 function updateStickyRange() { const elRect = stickyEl.getBoundingClientRect(); // 触发sticky的起始滚动位置 stickyRange.start = window.pageYOffset + elRect.top - 20; // 结束sticky的滚动位置(容器底部减去元素高度和padding) stickyRange.end = stickyRange.start + scrollContainer.offsetHeight - elRect.height - 100; } // 初始化区间计算,窗口 resize 时重新计算 updateStickyRange(); window.addEventListener('resize', updateStickyRange); window.addEventListener('scroll', () => { const currentScrollPos = window.pageYOffset; const isInStickyRange = currentScrollPos >= stickyRange.start && currentScrollPos <= stickyRange.end; if (isInStickyRange) { // 判断滚动方向:1=向下,-1=向上 const scrollDir = currentScrollPos > lastScrollPos ? 1 : -1; // 计算滚动速度(帧间滚动距离) const scrollSpeed = Math.abs(currentScrollPos - lastScrollPos); // 映射速度到旋转步长,系数可调整灵敏度 const rotationStep = scrollSpeed * 0.4; // 更新旋转角度,限制在0~900deg范围内 currentRotation += rotationStep * scrollDir; currentRotation = Math.max(0, Math.min(maxRotation, currentRotation)); // 应用旋转效果 stickyEl.style.transform = `rotate(${currentRotation}deg)`; } else { // 离开sticky区间时重置角度 if (currentRotation !== 0) { currentRotation = 0; stickyEl.style.transform = `rotate(0deg)`; } } lastScrollPos = currentScrollPos; }); // 用requestAnimationFrame优化动画流畅度 function smoothAnimate() { requestAnimationFrame(smoothAnimate); } smoothAnimate();
关键细节说明
- 粘性区间计算:通过
getBoundingClientRect()获取元素视口位置,结合滚动距离确定sticky生效的滚动范围,窗口大小变化时重新计算避免错位 - 滚动速度关联:用当前与上一帧的滚动位置差值作为速度,直接映射为旋转角度的变化步长,滚动越快旋转越快
- 角度边界控制:用
Math.max()和Math.min()确保旋转角度始终在0到900deg之间,不会出现过度旋转 - 平滑过渡:CSS的
transition配合JS动态更新transform,保证角度变化无生硬跳转
内容的提问来源于stack exchange,提问作者Михаил Щербаков
相关产品推荐
相关产品推荐

