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

如何实现滚动时的容器凸起弹跳效果?原方案失效求解决

滚动触发容器缩放与图片凸起弹跳效果实现方案

需求说明

开发一个页面效果:页面滚动时,固定容器内的图片随滚动位移,容器根据滚动速度伸缩,通过CSS transform实现中心元素的凸起弹跳(滚动时图片容器放大/缩小),参考同类设计网站的滚动视觉效果。

原代码问题分析

  • DOM加载顺序错误:HTML中<script>放在容器元素之前,JS执行时DOM尚未渲染,无法获取目标节点。
  • CSS语法错误:.container的width: 750缺少单位,应为750px。
  • 滚动速度计算逻辑错误:原代码用window.scrollY与容器高度的差值计算速度,无法反映实时滚动的快慢,应基于滚动位移的差值计算。
  • 容器滚动冲突:容器设置overflow-y: scroll,内部滚动与页面全局滚动冲突,导致效果无法触发。
  • 图片布局错误:flex-wrap: wrap导致图片换行排列,不符合垂直滚动位移的需求。

正确实现方案

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Scroll Bulge Effect</title>
  <link rel="stylesheet" href="style.css"> 
</head>
<body>
  <!-- 撑开页面高度,提供滚动空间 -->
  <div class="scroll-spacer"></div>
  
  <div class="container">
    <img src="img/img51.jpg" alt="Image 1" />
    <img src="img/img52.jpg" alt="Image 2" />
    <img src="img/img64.jpg" alt="Image 3" />
    <img src="img/img71.jpg" alt="Image 4" />
  </div>

  <script src="./js/app.js"></script>
</body>
</html>

CSS代码

body {
  margin: 0;
  background-color: rgb(110, 109, 109);
}

/* 撑开页面高度,确保用户能滚动触发效果 */
.scroll-spacer {
  height: 300vh;
}

.container {
  border-radius: 16px;
  height: 550px;
  width: 750px;
  max-width: 800px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  overflow: hidden;
  /* 图片垂直堆叠 */
  display: flex;
  flex-direction: column;
}

.container img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media only screen and (min-width: 350px) {
  .container {
    width: 80%;
  }
}

JavaScript代码

// 等待DOM完全加载后执行逻辑
document.addEventListener('DOMContentLoaded', () => {
  const container = document.querySelector('.container');
  const images = document.querySelectorAll('.container img');
  const containerHeight = container.offsetHeight;
  const centerPosition = window.innerHeight / 2;
  // 记录上一次滚动位置,用于计算滚动速度
  let lastScrollY = window.scrollY;

  function updateScrollEffect() {
    const currentScrollY = window.scrollY;
    // 计算实时滚动速度(位移差值,放大系数调整灵敏度)
    const scrollSpeed = Math.abs(currentScrollY - lastScrollY) * 0.5;
    lastScrollY = currentScrollY;

    // 容器缩放:限制缩放范围在0.8-1.2之间,避免过度变形
    const scaleFactor = Math.min(1.2, Math.max(0.8, 1 + scrollSpeed * 0.01));
    container.style.transform = `translate(-50%, -50%) scale(${scaleFactor})`;

    // 图片位移与凸起效果
    images.forEach((image, index) => {
      // 基础位移:随滚动同步垂直移动
      const baseTranslateY = -currentScrollY + (index * containerHeight);
      // 计算图片中心与页面中心的距离
      const imageCenterY = image.getBoundingClientRect().top + containerHeight / 2;
      const distanceFromCenter = Math.abs(centerPosition - imageCenterY);
      // 凸起强度:距离中心越近,凸起越明显
      const bulgeIntensity = Math.max(0, 1 - distanceFromCenter / (window.innerHeight / 2));
      const bulgeTranslateY = -scrollSpeed * bulgeIntensity * 0.3;

      image.style.transform = `translateY(${baseTranslateY + bulgeTranslateY}px)`;
    });
  }

  // 使用requestAnimationFrame优化动画流畅度
  function rafUpdate() {
    updateScrollEffect();
    requestAnimationFrame(rafUpdate);
  }

  requestAnimationFrame(rafUpdate);
});

关键实现说明

  1. DOM加载时机:用DOMContentLoaded确保JS在DOM渲染完成后执行,避免获取不到元素的问题。
  2. 滚动速度计算:通过对比当前与上一次的scrollY值,计算滚动位移差值,得到实时滚动速度。
  3. 容器缩放:基于滚动速度动态调整容器的scale值,限制缩放范围避免过度变形。
  4. 图片凸起逻辑:图片随滚动垂直位移,同时根据与页面中心的距离添加额外位移,距离中心越近,凸起效果越强。
  5. 性能优化:用requestAnimationFrame替代直接绑定scroll事件,确保动画流畅且性能友好。

PixiJS优化方案(可选)

如果需要更复杂的图形扭曲效果,可调整PixiJS代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>PixiJS Scroll Bulge Effect</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.1.3/pixi.min.js"></script>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow-x: hidden;
      background-color: #222222;
    }
    .scroll-spacer {
      height: 300vh;
    }
    #canvas-container {
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 80vw;
      height: 80vh;
      border-radius: 16px;
      overflow: hidden;
    }
  </style>
</head>
<body>
  <div class="scroll-spacer"></div>
  <div id="canvas-container"></div>

  <script>
    const canvasContainer = document.getElementById('canvas-container');
    const app = new PIXI.Application({
      width: canvasContainer.offsetWidth,
      height: canvasContainer.offsetHeight,
      backgroundColor: 0x222222
    });
    canvasContainer.appendChild(app.view);

    const container = new PIXI.Container();
    app.stage.addChild(container);

    const loader = new PIXI.Loader();
    const images = [
      'img/img51.jpg',
      'img/img52.jpg',
      'img/img64.jpg',
      'img/img71.jpg'
    ];
    images.forEach((img) => loader.add(img));
    loader.load(setup);

    let lastScrollY = window.scrollY;
    let imageSprites = [];

    function setup() {
      imageSprites = images.map((img, index) => {
        const texture = PIXI.Texture.from(img);
        const sprite = new PIXI.Sprite(texture);
        sprite.width = app.screen.width;
        sprite.height = app.screen.height;
        sprite.y = index * app.screen.height;
        container.addChild(sprite);
        return sprite;
      });

      app.ticker.add(() => {
        const currentScrollY = window.scrollY;
        const scrollSpeed = Math.abs(currentScrollY - lastScrollY) * 0.5;
        lastScrollY = currentScrollY;

        // 容器缩放
        const scale = Math.min(1.2, Math.max(0.8, 1 + scrollSpeed * 0.01));
        container.scale.set(scale);
        container.position.set(app.screen.width/2, app.screen.height/2);
        container.pivot.set(app.screen.width/2, app.screen.height/2);

        // 图片位移与中心凸起
        imageSprites.forEach((sprite) => {
          sprite.y = -currentScrollY + (imageSprites.indexOf(sprite) * app.screen.height);
          // 计算图片中心与容器中心的距离
          const centerY = app.screen.height / 2;
          const spriteCenterY = sprite.y + app.screen.height / 2;
          const distance = Math.abs(centerY - spriteCenterY);
          const bulge = Math.max(0, 1 - distance / (app.screen.height / 2)) * scrollSpeed * 0.5;
          sprite.y -= bulge;
        });
      });
    }
  </script>
</body>
</html>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:25:14