You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现类似AOS库的滚动触发动画?求简易跨端方案

实现类AOS的滚动触发动画(仅向下触发,向上恢复)

你的核心思路完全没问题——监听滚动事件,对比页面滚动距离和元素位置来切换状态,这正是这类滚动动画的核心逻辑!下面给你一套简易且兼容移动端/平板的原生实现方案,没有第三方依赖,能帮你彻底理解背后的原理:


1. 基础HTML结构

先给需要动画的元素标记一个统一类名,比如scroll-animate

<div class="scroll-animate">我是滚动触发动画的元素</div>
<p class="scroll-animate">另一个需要动画的段落</p>

2. CSS样式定义

先写元素的默认状态,再写动画激活状态,用CSS过渡实现平滑效果(也可以用关键帧动画,按需调整):

/* 默认状态:透明+上移,设置过渡动画 */
.scroll-animate {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s ease, transform 0.6s ease;
  /* 告诉浏览器提前优化这个元素的渲染,减少移动端卡顿 */
  will-change: opacity, transform;
}

/* 动画激活状态:可见+回到原位 */
.scroll-animate.animated {
  opacity: 1;
  transform: translateY(0);
}

3. 原生JavaScript核心逻辑

这里用原生JS实现,轻量且兼容性拉满(支持所有现代移动端/平板浏览器),核心做了3件事:

  • 防抖处理(避免滚动时频繁触发逻辑,提升性能)
  • 判断滚动方向(区分向上/向下)
  • 计算元素触发动画的位置
// 防抖函数:减少滚动事件的触发频率,优化性能
function debounce(func, delay = 10) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// 获取元素相对于文档顶部的距离(兼容嵌套元素)
function getElementAbsoluteTop(el) {
  let top = el.offsetTop;
  let parent = el.offsetParent;
  while (parent) {
    top += parent.offsetTop;
    parent = parent.offsetParent;
  }
  return top;
}

// 初始化变量
const animateElements = document.querySelectorAll('.scroll-animate');
let lastScrollPosition = window.pageYOffset || document.documentElement.scrollTop;

// 滚动逻辑处理函数
function handleScrollAnimation() {
  const currentScroll = window.pageYOffset || document.documentElement.scrollTop;
  const windowHeight = window.innerHeight;

  animateElements.forEach(el => {
    const elementTop = getElementAbsoluteTop(el);
    // 设置触发点:元素顶部距离视口底部还有70%窗口高度时触发(可自行调整比例)
    const triggerThreshold = elementTop - windowHeight * 0.7;

    // 向下滚动:滚动位置超过触发点,且元素未激活时添加动画类
    if (currentScroll > lastScrollPosition && currentScroll > triggerThreshold && !el.classList.contains('animated')) {
      el.classList.add('animated');
    }
    // 向上滚动:滚动位置回到触发点以下,且元素已激活时移除动画类
    else if (currentScroll < lastScrollPosition && currentScroll < triggerThreshold && el.classList.contains('animated')) {
      el.classList.remove('animated');
    }
  });

  // 更新上一次的滚动位置
  lastScrollPosition = currentScroll;
}

// 绑定防抖后的滚动事件
window.addEventListener('scroll', debounce(handleScrollAnimation));
// 页面加载时检查一次(避免元素一开始就在视口内却没触发动画)
window.addEventListener('load', handleScrollAnimation);

关键细节说明

  • 防抖函数:滚动事件每秒可能触发几十次,防抖能让逻辑只在滚动停止/减速时执行,大幅降低移动端的性能消耗
  • 触发阈值:设置成元素进入视口1/3左右时触发,符合用户的视觉预期,不会太突兀
  • 原生JS:不需要依赖jQuery,体积更小,移动端兼容性更好(甚至支持IE11,只需微调pageYOffset的降级逻辑)
  • will-change:提前告知浏览器元素的属性会变化,让浏览器做好渲染优化,减少移动端的滚动卡顿

兼容性调整(可选)

如果需要兼容IE11这类老浏览器,把window.pageYOffset替换成:

const currentScroll = document.documentElement.scrollTop || document.body.scrollTop;

你的初始思路完全抓住了核心,这套方案就是把你的想法落地,加上了性能优化和兼容性处理,代码量少,逻辑清晰,很适合用来理解滚动触发动画的原理!

内容的提问来源于stack exchange,提问作者Aaron

火山引擎 最新活动