使用GSAP构建分层缩放滚动效果

本教程详细讲解如何使用GSAP的ScrollSmoother和ScrollTrigger插件创建分层缩放滚动效果,包括浮动图片网格、主视觉分离文本动画和深度层次效果实现。

使用GSAP构建分层缩放滚动效果

学习如何使用GSAP的ScrollSmoother和ScrollTrigger插件重现Telescope网站的平滑分层缩放滚动动画,实现电影般深度感的滚动体验。

浮动图片网格

HTML结构

在开始动画之前,我们先从基础开始。布局可能看起来是解构的,但需要保持简单和可预测。

1
2
3
4
5
6
7
<div class="section">
  <div class="section__images">
    <img src="./img-1.webp" alt="Image" />
    <img src="./img-2.webp" alt="Image" />
    <!-- 更多图片 -->
  </div>
</div>

样式设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
.section__images {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  perspective: 100vh;

  img {
    position: absolute;
    width: 10vw;

    @media (max-width: 768px) {
      width: 20vw;
    }
  }
}

在样式设计方面,有几个重要注意事项。我们设置了一个全屏区域来包含所有浮动图片。该区域使用perspective值启用Z轴动画,为构图添加深度。在此区域内,每个图片都绝对定位以创建有机、分散的排列。

动画实现

首先,我们使用ScrollSmoother插件引入细微的滚动惯性,使滚动体验更加流畅精致。

1
2
3
4
5
6
7
const scroller = ScrollSmoother.create({
  wrapper: ".wrapper",
  content: ".content",
  smooth: 1.5,
  effects: true,
  normalizeScroll: true
})

我们只需要一个GSAP时间轴来处理整个动画。让我们使用ScrollTrigger插件开始设置。

1
2
3
4
5
6
7
8
9
this.timeline = gsap.timeline({
  scrollTrigger: {
    trigger: this.dom,
    start: "top top",
    end: "bottom top",
    scrub: true,
    pin: true
  }
})

接下来,我们通过沿Z轴移动小图片来为它们添加动画。为了使运动感觉更动态,我们添加了stagger,在每张图片之间引入小延迟。

1
2
3
4
5
6
7
8
9
this.timeline.to(this.smallImages, {
  z: "100vh",
  duration: 1,
  ease: "power1.inOut",
  stagger: {
    amount: 0.2,
    from: "center"
  }
})

主视觉和分离文本

现在我们已经构建了浮动图片网格,是时候专注于动画的核心部分——主图片和分开移动以显示它的文本。

HTML结构

1
2
3
4
5
<div class="section__media">
  <div class="section__media__back">
    <img src="./img-big.jpg" alt="Image" />
  </div>
</div>

样式设计

使用绝对定位将大图片添加为全尺寸覆盖,并定义一个CSS变量--progress,稍后我们将用它来控制动画。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.section__media {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  transform: scale(var(--progress));

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

对于图片动画,我们采用稍微不同的方法。我们不直接使用GSAP动画scale属性,而是在整个时间轴中动画一个名为--progress的CSS变量。

1
2
3
4
onUpdate: (self) => {
  const easedProgress = gsap.parseEase("power1.inOut")(self.progress)
  this.dom.style.setProperty("--progress", easedProgress)
}

接下来,我们添加文本元素,它分为两部分:一部分向左滑动,另一部分向右移动。

1
2
3
4
<h1>
  <span class="left">for the</span>
  <span class="right">planet</span>
</h1>

现在我们只需要在CSS中使用--progress变量来动画两侧的文本部分。

1
2
3
4
5
6
7
.left {
  transform: translate3d(calc(var(--progress) * (-66vw + 100%) - 0.5vw), 0, 0);
}

.right {
  transform: translate3d(calc(var(--progress) * (66vw - 100%)), 0, 0);
}

分层缩放和深度效果

前端图片层

我们首先在结构中添加"前端"图片,它们是背景图片的简单副本。这些图层将帮助我们创建添加深度和运动的拖尾缩放效果。

1
2
3
4
<div class="section__media__front front-1">
  <img src="./img-big.jpg" alt="Image" />
</div>
<!-- 更多前端图片层 -->

遮罩应用

我们将创建并添加主体(本例中为螃蟹)的遮罩,使其看起来像是从背景中弹出。

1
2
3
4
5
6
7
.section__media__front {          
  img {
    mask-image: url(./mask.png);
    mask-position: 50% 50%;
    mask-size: cover;
  }
}

分层缩放

我们逐步缩放每个图片层以创建深度感。第一个元素保持其原始大小,而每个后续图层稍微小一些,给人以它们进一步移动到背景中的印象。

1
2
3
4
5
6
.front-1 { transform: scale(1); }
.front-2 { transform: scale(0.85); }
.front-3 { transform: scale(0.6); }
.front-4 { transform: scale(0.45); }
.front-5 { transform: scale(0.3); }
.front-6 { transform: scale(0.15); }

最后,我们只需要在时间轴中再添加一个步骤,将所有图片层带回到其原始比例(scale: 1)。

1
2
3
4
5
6
this.timeline.to(this.frontImages, {
  scale: 1,
  duration: 1,
  ease: "power1.inOut",
  delay: .1,
}, 0.4)

模糊效果

为了使效果更加精致,我们可以在开始时为每个图层添加细微的模糊,然后在时间轴播放时将其动画消失。

1
2
3
.section__media__front {   
  filter: blur(2px);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
this.timeline.to(this.frontImages, {
  duration: 1,
  filter: "blur(0px)",
  ease: "power1.inOut",
  delay: .4,
  stagger: {
    amount: 0.2,
    from: "end"
  }
}, 0.6)

缩放和模糊动画相结合,分层缩放效果感觉丰富而沉浸。每个图层和谐移动,为动画提供深度和流畅性,同时保持整体体验的平滑和视觉平衡。

最终效果

这是实际运行的最终结果。缩放、模糊和平滑滚动的组合创建了干净的分层运动,感觉既自然又视觉上吸引人。细微的深度变化给人以3D场景在滚动时栩栩如生的印象,所有这些都只用几个精心定时的动画构建而成。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计