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

如何为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();

关键细节说明

  1. 粘性区间计算:通过getBoundingClientRect()获取元素视口位置,结合滚动距离确定sticky生效的滚动范围,窗口大小变化时重新计算避免错位
  2. 滚动速度关联:用当前与上一帧的滚动位置差值作为速度,直接映射为旋转角度的变化步长,滚动越快旋转越快
  3. 角度边界控制:用Math.max()和Math.min()确保旋转角度始终在0到900deg之间,不会出现过度旋转
  4. 平滑过渡:CSS的transition配合JS动态更新transform,保证角度变化无生硬跳转

内容的提问来源于stack exchange,提问作者Михаил Щербаков

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:10:27