GSAP 实现 iPhone15 概览页按钮动画

1,823 阅读4分钟

在浏览 iPhone15 概览页时,它的按钮动画引起了我的兴趣:

GIF 2023-10-8 14-33-38.gif

本篇文章将借助 js 动画库 GSAP (GreenSock Animation Platform) 对如上图所示的按钮出现和隐藏动画进行实现。

GSAP 初体验

首先来实现黑色圆放大出现的动画以了解 gsap 的基本用法,它的 html + css 代码很简单:

<div id="btn"></div>
#btn {
  width: 56px;
  height: 56px;
  border-radius: 28px;
  background-color: rgb(66 66 69);
}

效果如下:

image.png

现在开始添加动画,直接使用 cdn 的形式引入 gsap,如此在 window 对象上就会添加 gsap 对象。

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>

通过 gsap.timeline() 创建时间线实例 tl

const tl = gsap.timeline()

有了动画时间线,就可以方便我们添加一系列的补间动画,并让它们按顺序依次播放。先通过 tl.from() 让圆从我们传入的状态变换到前面用 css 定义的应该呈现的状态:

tl.from('#btn', {
  scale: 0,
  transformOrigin: 'bottom',
  duration: 1,
  ease: 'power1.in'
})

tl.from() 的第 1 个参数为添加动画的目标元素,我们传入的'#btn',gsap 会传给 document.querySelectorAll();第 2 个参数是一个对象,里面可以放 css 属性或是其它一些特殊属性比如 onComplete: () => {} 用于定义该补间动画完成时要执行的代码。下面介绍用到的几个属性:

  • scale: 0 的作用相当于给圆的初始样式添加上 transform: scale(0, 0),除了缩放,其它关于 transform 的缩写在 gsap 官网中有如下表格进行了说明:

image (1).png

transformOrigin 的值也可以直接使用 'bottom' 这样的字符串;

  • duration: 1 代表动画的持续时间为 1s,默认值为 0.5
  • ease 用于描述动画的速率曲线,其不同值所代表的意义在官网中也有个演示可以直观地感受:

GIF 2023-10-8 15-40-52.gif

power1.in 表示动画将先慢后快。

通过简单的配置,一个黑色实心圆从底部由小到大出现的动画就实现了:

GIF 2023-10-8 15-55-51.gif

在创建时间线实例时,也可以传入一些配置:

const tl = gsap.timeline({
  repeat: -1, // 一直重复
  yoyo: true, // 下一次循环,动画会以相反的方向运行
  repeatDelay: 1 // 重复动画前等待 1 s
})

那么动画效果如下:

GIF 2023-10-8 16-04-28.gif

完成按钮动画

在了解完第一个动画效果的实现原理后,之后无非是通过链式调用不同的方法(除了 fromto,时间线实例还有很多方法,可参见官方文档),给各个元素依次添加上动画效果而已,from 是设置从某个初始状态到当前状态(也就是没有添加动画时的状态)的动画,而 to 方法是设置从当前状态要到达的目标状态:

tl.from(['#btn', '#blue-circle'], {
  scale: 0,
  duration: 1,
  ease: 'power1.in',
  stagger: 0.5
})
  .to('#blue-circle', {
    scale: 0
  })
  .from('#icon', {
    scale: 0
  })
  .to('#btn', {
    width: 200
  })
  .to(
    '#icon',
    {
      x: 50
    },
    '<'
  )
  .from(
    '.text',
    {
      opacity: 0,
      x: -12
    }
  )

下面做一些特别说明:

  • fromto,这些方法的第 1 个参数还可以是个数组,表明数组里的元素都将应用相同的动画配置,stagger: 0.5 表示 #blue-circle 的动画会比 #btn 的晚开始 0.5s;
  • 第 21 行的 '<' 表示 #icon 的 x 轴平移动画和上一个补间动画,即 #btn 的宽度变为 200px 一起开始;
  • 具体的 html 和 css 等完整代码我会通过码上掘金展示。

至此,按钮动画如下:

GIF 2023-10-8 16-29-56.gif

使用 ScrollTrigger 插件

iPhone15 概览页的效果是当页面滚动到指定的区域,按钮才会出现,页面离开指定区域则按钮消失。我们可以借助 gsap 提供的 ScrollTrigger 插件来实现这一效果,插件需要单独引入 cdn:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>

使用前先注册插件:

gsap.registerPlugin(ScrollTrigger)

然后在创建时间线实例时,传入参数如下:

const tl = gsap.timeline({
  scrollTrigger: {
    trigger: '.box',
    start: 'top 80%', // 开始位置
    onLeaveBack: () => {
      tl.reverse()
    }
  }
})
  • scrollTrigger.trigger 用于指定触发时间线动画的元素;
  • start: 'top 80%' 表示当 .box 的顶部与浏览器滚动条从上往下算 80% 长度的区域相遇时,开始触发动画:

image (2).png

  • onLeaveBack 即当滚动条往上回滚,移动超过了 start 指定的位置时(具体说就是滚动条 80% 的位置位于按钮的顶部的上方)触发的回调,我直接使用 tl.reverse() 让整个时间线动画反转,而没有像iPhone15 概览页效果那样再进行些动画的设计了。

最终效果

感谢.gif 点赞.png