Gsap从入门到入土(巨详细
1、GSAP概念
GSAP
是一个功能强大的动画库。它可以灵活控制CSS
动画属性、SVG
路径动画、数字、字符串、WebGL
等。还支持React
、Vue
等主流框架,可以结合Threejs
、PixiJs
实现一些复杂的3D动效场景。
官网地址:https://gsap.com/
较为优质的中文文档:https://gsap.framer.wiki/
除了GSAP
核心库外,还有很多实用的插件,比如结合ScrollTrigger插件来实现Web网站的滚动动画效果
2、技术选型 - 为什么选择GSAP
GreenSock
动画平台(GSAP
)是一个业界知名的工具套件,用于1100多万个网站,其中超过50%的获奖网站。在任何框架中,你都可以使用GSAP
来动画化JavaScript
可以触及的任何东西。无论你想动画UI,SVG
,Three.js
或React
组件
特点:
- 小的javascript文件
- 消除了所有主要浏览器的兼容性问题
- 相较于css动画,更易于使用
- 自称地球上最强大动画库
- 高性能,适用范围广
我觉得它可以称为一个动画框架,因为它的生态实在是太健全了,从简单动画,到拖拽,到滚动触发,应有尽有,几乎你能想象到的网页动画在它这里都可以实现,并且只需要使用它一个框架。但是不知道为什么,这么厉害的东西,在国内很少有关于它的资料。我觉得它不火的原因可能是因为功能太多太复杂,往往一个界面不需要这么多动画,使用简单的Animate.css库就可以满足日常开发的需求。
3、入门案例:心爱的小摩托
1、准备基础环境
- 首先我们需要引用核心的JS文件:
gsap.min.js
- 其次再引用一个简易版的常用图标
CSS
库,这里有我们心爱的小摩托图标文件:https://maxcdn.bootstrapcdn.com/fontawesome/4.4.0/css/font-awesome.min.css
- 接下来我们准备
HTML
内容,示例代码如下:
<div class="sky">
<i class="fa fa-motorcycle"></i>
</div>
<div class="ground"></div>
i 标签的内容就是引入 font-awesome 图标库的小摩托图标
CSS代码:
body { margin: 0; }
.fa-motorcycle {
color: #333;
font-size: 50px;
line-height: 30px;
margin-top: 68px;
margin-left: 20px;
}
.sky {
background-color: #adf;
height: 100px;
}
.ground {
background-color: #778;
width: 100%;
height: 30px;
}
完成后的界面效果,如下图所示:
淡蓝色好比天空,灰色好比地面,地面上停了一辆酷酷的黑色摩托车,准备工作到此完成,我们来利用 GSAP
的 API
开动摩托车吧!
2、使用 gsap.to()
方法,让小摩托向前600px
gsap.to()
就是告诉动画对象,最终要达到的运动状态,这个函数有两个关键参数:
- 第一个参数告知需要绑定哪个动画对象
- 第二个参数就是要告知动画最终效果的对象:动画时长、是旋转还是位移变化、或者其它属性的变化
对应JS代码如下:
const cycle=document.querySelector(".fa-motorcycle"); // 小摩托图标
gsap.to(cycle,{
duration:2,
x:"600px"
});
上述代码告知我们的小摩托,需要在2秒内向前开动600px
,duration
是动画时长的设定,x表示在横轴方向位移,这里你还可以用left:"600px"
, 但是你需要在CSS的 .fa-motorcycle
中添加 position: relative
属性,否则你看不到动画效果。
3、使用 gsap.from()
方法,让小摩托向前600px
gsap.from()
就是告诉动画对象,最终要达到的运动状态,这个函数有两个关键参数:
这个函数的功能与gsap.from()
的调用方法一致,你需要告知函数现有的状态是从原来的哪个状态转换过来的,就好像把过去发生的动作回放
了一遍 。
首先我们修改 .fa-motorcycle
类 ,让摩托车先向右移动600px
.fa-motorcycle{
color: #333;
font-size: 50px;
line-height: 30px;
margin-top: 68px;
margin-left: 20px;
position: relative;
left: 600px; //一开始让小车在600米处
}
JS文件:
const cycle = document.querySelector(".fa-motorcycle");
gsap.from(cycle,{
duration:5,
left:"0px"
});
此时发现效果一致,可以得出gsap.from
其实就是gsap.to
的“相反操作
”
4、多个动画同时执行,让小摩托更加拉风
接下来,为了让我们骑着心爱的小摩托更加拉风,我们让动画由远及近逐渐显示,同时并非直线骑行,往下移动20px
。这些动作都是同时进行的,我们可以同时添加多个gsap.from()
或gsap.to()
,示例代码如下:
const cycle=document.querySelector(".fa-motorcycle");
gasp.to(cycle,{
duration:2,
x:"600px"
});
gsap.from(cycle,{
duration: 2,
opacity:0
});
gasp.to(cycle,{
duration:2,
y:"20px"
});
这里我们用到了opacity
属性,让我们的小摩托先隐藏起来,然后逐渐显示;y:"20px"
,其意思就是往下移动20px
。
5、多个动画属性写在一起,变成蓝色小摩托
const cycle = document.querySelector(".fa-motorcycle");
gsap.to(cycle,{
duration:2,
x:"600px",
y:"20px",
color:"blue"
});
6、添加过渡效果,让小摩托运动更加自然
为了让运动效果更加自然,我们需要添加一些过渡效果,比如css
动画里常见的linear
,ease-in
,ease-out
,ease-in-out
,这些运动效果,GSAP
也是支持的,这里使用了 ease-in-out
这个属性,慢慢加速起来然后慢慢停下来,如下代码所示:
const cycle = document.querySelector(".fa-motorcycle");
gsap.to(cycle,{
duration:2,
x:"600px",
ease:Power4.easeInOut
});
这里你可能注意到了,我们这里使用了Power4
,这个属性,其实这个属性有 Power0~4
这几个属性,这个属性从低到高依次增强动画的运动属性,感兴趣的话可以亲自尝试下。
7、添加 Transformation 变换属性,秀一把车技
学了这么多,接下来我们秀一把车技,将车把抬高45度
,在加一些反弹动效,让效果更加接近真实的物理世界。这里我们用到了rotation
属性,进行角度的旋转,以及Bounce
反弹的动效属性,最后别忘记改变角度旋转的作用点,是在车后轮,这里用到了transformOrigin
进行更改,最终完成的代码效果如下图所示:
const cycle=document.querySelector(".fa-motorcycle");
gsap.to(cycle,{
duration:2,
x:"600px",
ease:Power2.easeOut,
});
gsap.from(cycle,{
duration:1,
rotation:-45,
transformOrigin:"10px bottom",
ease:Bounce.easeOut
});
4、主要功能介绍
补间动画
适用于控制单个元素的属性变化
有四种Tween
的动画方式
gsap.to(targets, vars)
- 这是一种最常用的tween动画,就是让元素从初始状态变化到目标状态。gsap.from(targets, vars)
- 有点像to方法的逆向变化,就是让元素从目标状态变化到初始状态。gsap.fromTo(targets, vars, vars)
- 需要自己定义两个状态的数据,然后从前一个变化到后一个。gsap.set(targets, vars)
- 直接设置成想要的状态,没有任何过度与动画效果。
时间线Timeline
当需要控制多段动画,并且动画之间还有先后执行顺序的时候,时间线能够很好处理。
// 通过一个变量保存对Tween或者Timeline实例的引用
let tween = gsap.to("#logo", {duration: 1, x: 100});
// 暂停
tween.pause();
// 恢复(继续)
tween.resume();
// 反向变化
tween.reverse();
// 直接切换到整个动画变化时长的0.5秒的时间点的状态
tween.seek(0.5);
// 直接切换到整个变化过程的1/4的节点的状态
tween.progress(0.25);
// 让运动减速到0.5倍
tween.timeScale(0.5);
// 让变化加速到原来的2倍
tween.timeScale(2);
// 直接销毁tween实例,让垃圾回收机制可以处理该实例所占用的内存
tween.kill();
关键帧动画
支持传入对象数组的形式。
可以通过给某个动画设置delay来让动画之间产生一定的间隔(delay
是正值)或者重叠(delay
是负值)。
关键帧动画的默认动画曲线是线性的,可以在每个动画中都重新定义ease
的设置,也可以给整个关键帧动画添加一个统一的的动画曲线设置。
gsap.to(".elem", {
keyframes: [
{x: 100, duration: 1, ease: 'sine.out'}, // 定义这个分段动画自己的ease曲线
{y: 200, duration: 1, delay: 0.5}, // 产生和前个分段动画0.5秒的间隔
{rotation: 360, duration: 2, delay: -0.25} // 和前一个分段动画产生0.25秒的重叠
],
ease: 'expo.inOut' // 设置整个关键帧动画的曲线
});
支持以百分比帧率的形式(这个方式跟css
的 keyframes
形式恨相近)
gsap.to(".elem", {
keyframes: {
"0%": { x: 100, y: 100},
"75%": { x: 0, y: 0, ease: 'sine.out'}, // 指定这个分段的动画曲线
"100%": { x: 50, y: 50 },
easeEach: 'expo.inOut' // 每个分段的动画曲线
},
ease: 'none' // 整个关键帧动画的动画曲线
duration: 2,
})
其他配置
默认配置
指定默认全局配置, 创建的补间动画或是时间线会继承默认配置,如果单独配置则会覆盖默认配置// 设置动画的缓动函数默认为线性匀速,并且开启3D渲染模式
gsap.defaults({
ease: 'none',
force3D:true
});
5、动效整理
开场动画
时间线(timeline)
设定好每个步骤的动画参数,
timeline
会按照时间轴逐步播放 <和<-=2是时间线(timeline
)控制的特殊语法
<
(小于号): 这个符号表示"与前一个动画同时开始"。它将新的动画(或一组动画)的开始时间设置为与前一个动画相同的时间点。<-=2
: 这个符号是<
的一个变体,它的含义是"从前一个动画开始时间的2秒前开始"。<
:部分表示相对于前一个动画-=2
:部分表示从那个时间点往前移动2秒
(就是原本要等上一个动画结束才开始,-=2
就是比上一个动画提前2秒
开始)
整体效果实现
1. 从底部向上传入的卡片动画
gsap.timeline()
.from(cardList, {
y: window.innerHeight / 2 + image.clientHeight * 1.5,
rotateX: -180,
stagger: 0.1,
duration: 0.5,
opacity: 0.8,
scale: 3,
})
先设置卡片的初始垂直位置在屏幕底部:window.innerHeight / 2
是屏幕中心的高度,加上image.clientHeight * 1.5
,使得卡片的初始位置在屏幕底部下方。然后设置卡片的初始旋转角度为-180
度,使其背面朝上,再设置动画效果逐个延迟开始,每个卡片延迟0.1
秒,初始缩放值为3倍
大小
2. 设置变换原点:
.set(cardList, {
transformOrigin: `center ${radius1 + image.clientHeight / 2}px`,
})
将所有卡片的变换原点都设置在一个共同的中心点进行旋转
3. 初始圆形展开排列:
.to(cardList, {
rotation: index => {
return (index * 360) / count
},
rotateY: 15,
duration: 1,
ease: 'power1.out',
}, '<')
-
rotation
: 这是一个函数,为每张卡片设置不同的旋转角度。 -
index * 360 / count
:计算每张卡片的旋转角度。保证卡片均匀分布在圆角上 -
<
:表示这个动画与前一个动画同时开始
4. 圆形按照半径扩散展开:
.to(cardList, {
x: index => {
return Math.round(radius2 * Math.cos(sliceAngle * index - Math.PI / 4))
},
y: index => {
return Math.round(radius2 * Math.sin(sliceAngle * index - Math.PI / 4)) - radius1
},
rotation: index => {
return (index + 1) * (360 / count)
},
})
这一步使用三角函数计算每个卡片在圆上的 x
和 y
坐标,同时调整旋转角度,使卡片始终朝向圆心。
5. 持续旋转:
.to('.group', {
rotation: 360,
duration: 20,
repeat: -1,
ease: 'none',
}, '<-=2')
<
: 表示当前动画与前一个动画同时开始。-=2
: 表示当前动画的开始时间比前一个动画的结束时间提前2秒。 这里对包含所有卡片的容器元素进行持续旋转,使整个卡片组绕圆心旋转。
文字模糊过渡效果
1. 滚动吸顶效果
当目标容器滚动到页面顶部时,它会被固定在那里,类似吸顶的效果(可以看到动图中滚动条在往下走,内容是固定不变的)
当目标容器滚动到页面顶部时,它会被固定在那里,类似吸顶的效果(可以看到动图中滚动条在往下走,内容是固定不变的)
gsap.timeline({
scrollTrigger: {
trigger: box, // 触发的目标元素
start: `top top`, // 当目标元素的顶部滚动到屏幕顶部时触发
end: `bottom top`, // 当目标元素的底部滚动到屏幕顶部时结束
pin: true, // 固定目标元素
pinSpacing: false, // 不自动调整间距
scrub: true, // 滚动时平滑动画
markers: false, // 开启标记,调试时可用
},
})
滚动吸附效果核心是依赖开启pin配置
pin: true
: 这是实现滚动吸附的关键属性。当设置为 true 时,它会在滚动触发器激活期间将目标元素固定在其触发位置。pinSpacing: false
:当pinSpacing
设置为false
时,目标元素的底部滚动到屏幕顶部时解除固定;当pinSpacing
设置为true
时,会给固定元素添加一个等同于元素自身高度的padding-bottom
空间。这意味目标元素的底部滚动到屏幕顶部时还需要再滚动一个元素自身高度的距离才会解除固定,当然pinSpacing
还可以接受一个数值,用来指定添加的空间高度。
2.文字模糊到清晰扩散效果
- 将每个英文字母拆分成一个个
span
元素:
window.Splitting()
: 使用Splitting.js
库将文本分割成单个字符(或单词) - 给每个
span
元素创建动画
○ 主要对旋转角度、滤镜模糊度、Y周偏移、缩放等参数做变化 - 每个
span
元素同样配置scrollTrigger
功能来做一个动画进度跟随滚动位置变化的效果随着用户滚动 - 文字逐渐从中心向两侧展开的过渡:
stagger: {
amount: 0.15,
from: 'center',
}
- 错开的效果主要是依赖了
gsap
的stagger
属性-
amount
是设置这组文字也就是每个span动画开始的时间间隔 -
from: center
这定义了交错动画的起始点。‘center
’ 意味着动画将从中心元素开始,然后向两边扩散。
-