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

基于滚动值实现三张横向卡片的动画效果

横向卡片滚动视差动画实现优化

我有三张横向排列的卡片,想要实现类似某站点Result Section的滚动视差动画效果,目前编写了一段JS代码,但运行效果不符合预期,以下是我的代码,求优化:

window.addEventListener('scroll', () => {
    const cardOne = document.getElementById("box_one")
    const cardTwo = document.getElementById("box_two")
    const cardThree = document.getElementById("box_three")
    const scrollYValue = window.scrollY;

    $(window).scroll(function () { 
      if ($(window).scrollTop() > $('body').height() / 2) {
        const cardOne = document.getElementById("box_one")
        const cardTwo = document.getElementById("box_two")
        const cardThree = document.getElementById("box_three")
        const scrollYValue = window.scrollY;
        
        $(window).scroll(function() {
          var position = $(window).scrollTop();
          var scroll = $(window).scrollTop();
            // console.log(scroll, position);
            if (scroll >= position) {
              console.log("Up");
                cardOne.style.transform = "translate3d(0px, " + -scrollYValue / 200 + "em, 0px)",
                cardTwo.style.transform = "translate3d(0px, " + -scrollYValue / 600 + "em, 0px)",
                cardThree.style.transform = `translateY(${scrollYValue / 30}px)`
              } else if (scroll <= position) { 
                console.log("back");
                cardOne.style.transform = "translate3d(0px, " + scrollYValue  + "px, 0px)",
                cardTwo.style.transform = `translateY(${-scrollYValue / 90}px)`
                cardThree.style.transform = `translateY(${-scrollYValue / 30}px)`
            }
            position = scroll;
        });
      } 
    });
  })

代码存在的问题

  1. 重复绑定scroll事件:外层已通过原生JS绑定scroll事件,内部又嵌套两次jQuery的scroll绑定,会导致事件多次触发,严重影响性能,甚至出现动画抖动。
  2. DOM元素重复获取:每次scroll都重新调用getElementById,完全没必要,应该初始化时缓存元素。
  3. 滚动方向判断失效:position和scroll初始值都是当前scrollTop,后续position = scroll会导致scroll >= position永远成立,"back"分支永远不会执行。
  4. 单位混用:动画同时使用em和px,导致动画速度不协调,视觉效果混乱。
  5. 触发条件不合理:用body高度的一半作为触发时机,应该判断卡片是否进入视口,避免在页面其他区域滚动时触发无用动画。

优化后的实现方案

核心思路

  • 缓存DOM元素,减少重复查询
  • 仅绑定一次scroll事件,避免重复触发
  • 用IntersectionObserver判断卡片区域是否进入视口,仅在可视范围内执行动画
  • 正确记录上一次滚动位置,判断滚动方向
  • 统一动画单位,调整视差参数,模拟目标效果

完整代码

HTML结构示例
<div class="cards-container">
  <div class="card" id="box_one">卡片1</div>
  <div class="card" id="box_two">卡片2</div>
  <div class="card" id="box_three">卡片3</div>
</div>
CSS基础样式
.cards-container {
  display: flex;
  gap: 2rem;
  justify-content: center;
  margin: 100vh 0; /* 让卡片处于页面中间,方便测试滚动 */
}

.card {
  width: 300px;
  height: 400px;
  background: #fff;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  position: relative;
}
JS代码
// 缓存DOM元素
const cardOne = document.getElementById("box_one");
const cardTwo = document.getElementById("box_two");
const cardThree = document.getElementById("box_three");
const cardsContainer = document.querySelector(".cards-container");

let lastScrollTop = 0;
let isAnimating = false;

// 监听卡片区域是否进入视口
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    isAnimating = entry.isIntersecting;
  });
}, { threshold: 0.1 });

observer.observe(cardsContainer);

// 绑定一次scroll事件
window.addEventListener('scroll', () => {
  if (!isAnimating) return;

  const scrollTop = window.scrollY;
  // 判断滚动方向
  const isScrollUp = scrollTop < lastScrollTop;

  // 计算视差偏移量(可根据需求调整系数)
  const offsetFactor = scrollTop * 0.02;

  if (isScrollUp) {
    // 向上滚动时的动画
    cardOne.style.transform = `translateY(${offsetFactor * 1.5}px)`;
    cardTwo.style.transform = `translateY(${offsetFactor * 0.8}px)`;
    cardThree.style.transform = `translateY(${offsetFactor * 0.3}px)`;
  } else {
    // 向下滚动时的动画
    cardOne.style.transform = `translateY(${-offsetFactor * 1.5}px)`;
    cardTwo.style.transform = `translateY(${-offsetFactor * 0.8}px)`;
    cardThree.style.transform = `translateY(${-offsetFactor * 0.3}px)`;
  }

  lastScrollTop = scrollTop;
}, { passive: true });

说明

  • 调整offsetFactor后的系数可以控制每张卡片的滚动速度差,系数越大,视差效果越明显
  • IntersectionObserver确保只有卡片进入视口时才执行动画,提升页面性能
  • 使用passive: true优化滚动事件的性能,避免浏览器卡顿

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:15:27