当前位置:Gxlcms > css > 如何使用CSS和GSAP实现有多个关键帧的连续动画(附源码)

如何使用CSS和GSAP实现有多个关键帧的连续动画(附源码)

时间:2021-07-01 10:21:17 帮助过:17人阅读

本篇文章给大家带来的内容是关于如何使用CSS和GSAP实现有多个关键帧的连续动画(附源码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

效果预览


4094838559-5b985d3ec76bc_articlex.gif

源代码下载

https://github.com/comehope/front-end-daily-challenges

代码解读

定义 dom,容器中包含 10 个 p 子元素,每个 p 中包含 1 个 span 元素:

  1. <figure class="container">
  2. <div><span></span></div>
  3. <div><span></span></div>
  4. <div><span></span></div>
  5. <div><span></span></div>
  6. <div><span></span></div>
  7. <div><span></span></div>
  8. <div><span></span></div>
  9. <div><span></span></div>
  10. <div><span></span></div>
  11. <div><span></span></div>
  12. </figure>

居中显示:

  1. body {
  2. margin: 0;
  3. height: 100vh;
  4. display: flex;
  5. align-items: center;
  6. justify-content: center;
  7. background-color: lightyellow;
  8. }

定义容器的尺寸和样式:

  1. .container {
  2. width: 400px;
  3. height: 400px;
  4. background: linear-gradient(45deg, tomato, gold);
  5. border-radius: 3%;
  6. box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  7. }

画出容器里的 1 个元素,它有一个外壳 p,里面是一个白色的小方块 span

  1. .container {
  2. position: relative;
  3. }
  4. .container p {
  5. position: absolute;
  6. width: inherit;
  7. height: inherit;
  8. display: flex;
  9. align-items: center;
  10. justify-content: center;
  11. }
  12. .container p span {
  13. position: absolute;
  14. width: 40px;
  15. height: 40px;
  16. background-color: white;
  17. }

为容器中的元素定义下标变量,并让元素的外壳依次旋转,围合成一个圆形,其中 outline 是辅助线:

  1. .container p {
  2. outline: 1px dashed black;
  3. transform: rotate(calc((var(--n) - 1) * 36deg));
  4. }
  5. .container p:nth-child(1) { --n: 1; }
  6. .container p:nth-child(2) { --n: 2; }
  7. .container p:nth-child(3) { --n: 3; }
  8. .container p:nth-child(4) { --n: 4; }
  9. .container p:nth-child(5) { --n: 5; }
  10. .container p:nth-child(6) { --n: 6; }
  11. .container p:nth-child(7) { --n: 7; }
  12. .container p:nth-child(8) { --n: 8; }
  13. .container p:nth-child(9) { --n: 9; }
  14. .container p:nth-child(10) { --n: 10; }

至此,子元素绘制完成,接下来开始写动画脚本。
引入 GSAP 库:

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

定义一个变量,代表子元素选择器:

  1. let elements = '.container p span';

声明一个时间线对象:

  1. let animation = new TimelineMax();

先设定入场方式为由小(第1帧)变大(第2帧),其中并没有第 2 帧的代码,它是隐含在语义中的:

  1. animation.from(elements, 1, {scale: 0});

让子元素变成竖长条,向四周散开(第3帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25});

让竖长条旋转着变成小方块(第4帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180});

让小方块变成横长条,围成一个圆形(第5帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1});

注意,因 scrimba 在录制过多帧时会崩溃,所以第 6 帧至第 11 帧没有在视频中体现。
让圆形向内收敛,同时线条变细(第6帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1});

让线条向左摆动(第7帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'});

再让线条向右摆动(第8帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'});

再把横线变为竖线,造型与第 3 帧相似,只是线更细,更向内收敛(第9帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'})
  8. .to(elements, 1, {x: '0', scaleX: 0.1, scaleY: 1});

再把竖线变为横线,造型与第 5 帧相似,但线短一些(第10帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'})
  8. .to(elements, 1, {x: '0', scaleX: 0.1, scaleY: 1})
  9. .to(elements, 1, {scaleX: 0.5, scaleY: 0.1})

横线稍向外扩散,变为圆点(第11帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'})
  8. .to(elements, 1, {x: '0', scaleX: 0.1, scaleY: 1})
  9. .to(elements, 1, {scaleX: 0.5, scaleY: 0.1})
  10. .to(elements, 1, {y: '-80px', scaleY: 0.5, borderRadius: '50%'});

让圆点变形为竖线,并向内收缩,这个变化的距离长,所以动画时间也要长一些(第12帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'})
  8. .to(elements, 1, {x: '0', scaleX: 0.1, scaleY: 1})
  9. .to(elements, 1, {scaleX: 0.5, scaleY: 0.1})
  10. .to(elements, 1, {y: '-80px', scaleY: 0.5, borderRadius: '50%'})
  11. .to(elements, 1, {y: '-10px', scaleX: 0.1, scaleY: 0.5, borderRadius: '0%', rotation: 0});

让竖线从中心向外快速扩散,扩散前稍停片刻,好像线条都被发射出一样(第13帧):

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'})
  8. .to(elements, 1, {x: '0', scaleX: 0.1, scaleY: 1})
  9. .to(elements, 1, {scaleX: 0.5, scaleY: 0.1})
  10. .to(elements, 1, {y: '-80px', scaleY: 0.5, borderRadius: '50%'})
  11. .to(elements, 1, {y: '-10px', scaleX: 0.1, scaleY: 0.5, borderRadius: '0%', rotation: 0})
  12. .to(elements, 1, {y: '-300px', delay: 0.5});

用时间尺度缩放函数让动画播放速度加快一倍:

  1. animation.from(elements, 1, {scale: 0})
  2. .to(elements, 1, {y: '-100px', scaleX: 0.25})
  3. .to(elements, 1, {scaleY: 0.25, rotation: 180})
  4. .to(elements, 1, {scaleX: 1})
  5. .to(elements, 1, {y: '-60px', scaleY: 0.1})
  6. .to(elements, 1, {x: '-30px'})
  7. .to(elements, 1, {x: '30px'})
  8. .to(elements, 1, {x: '0', scaleX: 0.1, scaleY: 1})
  9. .to(elements, 1, {scaleX: 0.5, scaleY: 0.1})
  10. .to(elements, 1, {y: '-80px', scaleY: 0.5, borderRadius: '50%'})
  11. .to(elements, 1, {y: '-10px', scaleX: 0.1, scaleY: 0.5, borderRadius: '0%', rotation: 0})
  12. .to(elements, 1, {y: '-300px', delay: 0.5})
  13. .timeScale(2);

修改声明时间线的代码,使动画重复播放:

  1. let animation = new TimelineMax({repeat: -1, repeatDelay: 1});

至此,动画完成。
隐藏容器外的内容,并删掉辅助线;

  1. .container {
  2. overflow: hidden;
  3. }
  4. .container p {
  5. /* outline: 1px dashed black; */
  6. }

最后,装饰一下页面的角落:

  1. body {
  2. overflow: hidden;
  3. }
  4. body::before,
  5. body::after {
  6. content: '';
  7. position: absolute;
  8. width: 60vmin;
  9. height: 60vmin;
  10. border-radius: 50%;
  11. background: radial-gradient(
  12. transparent 25%,
  13. gold 25%, gold 50%,
  14. tomato 50%
  15. );
  16. }
  17. body::before {
  18. left: -30vmin;
  19. bottom: -30vmin;
  20. }
  21. body::after {
  22. right: -30vmin;
  23. top: -30vmin;
  24. }

大功告成!

相关推荐:

如何使用纯CSS实现一把剪刀的效果(附源码)

如何使用纯CSS实现条纹错觉的动画效果(附源码)

以上就是如何使用CSS和GSAP实现有多个关键帧的连续动画(附源码)的详细内容,更多请关注Gxl网其它相关文章!

人气教程排行