Skip to content

多元素组合动画 - 抛物线

Published:

简单的思路

<div class="ball" />
.ball {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  left: 100px;
  top: 300px;
  animation: move 2s infinite;
  background: red;
  position: relative;
}

@keyframes move {
  to {
    transform: translate(100px, 500px);
  }
}

如果只是简单粗暴地添加 translate 属性,那么动画的效果是不尽人意。

动作分解

抛物线可以把它看作是两个方向的运动,首先一个是水平方向匀速移动,第二是竖直方向自由落体移动。

尝试两个动画

@keyframes moveX {
  to {
    transform: translateX(100px);
  }
}
@keyframes moveY {
  to {
    transform: translateY(500px);
  }
}

.ball {
  animation:
    moveX 2s linear infinite,
    moveY 2s linear infinite;
}

可以看到,动画已经变形了。因为这两个动画都改变了transform,导致了相互影响。本来 moveX 是横向移动100个像素,而 transform 又改动了,不横向移动了,又变成纵向移动500个像素,相互冲突。

尝试两个元素

将小球作为子元素,父元素负责水平方向的移动,子元素负责竖直方向的移动。

<div class="ball">
  <div class="inner" />
</div>
.ball {
  position: fixed;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: 1px dashed #aaa;
  left: 100px;
  top: 300px;
  animation: moveX 2s linear infinite;
}
.inner {
  background: #fc5e56;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  animation: moveY 2s linear infinite;
}

@keyframes moveX {
  to {
    transform: translateX(100px);
  }
}
@keyframes moveY {
  to {
    transform: translateY(500px);
  }
}

可以看到,带有虚线边框的父元素带着子元素水平方向移动,随后子元素竖直方向移动。

带点优化

.inner {
  background: #fc5e56;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  animation: moveParabola 2s ease-in-out infinite;
}

@keyframes moveX {
  to {
    transform: translateX(100px);
  }
}

@keyframes moveParabola {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-100px); /* 顶点,向上运动 */
  }
  100% {
    transform: translateY(360px); /* 回到起始高度 */
  }
}