在 CSS 下落动画中创建类似重力的效果并在使用 rotateX 时计算 'circle' 半径的变化

Creating a gravity-like effect in CSS falling animation and calculating change of radius of a 'circle' when using rotateX

我有以下球落下并弹回的动画:

body {
  margin: 0;
  padding: 0;
}

.ball {
  width: 20px;
  height: 20px;
  
  margin: 0 auto;
  
  border-radius: 50%;
  background-color: black;
  
  animation: bounce 2s infinite linear;
}

.ground {
  display: block;
  width: 100%;
  
  border-bottom: 1px solid black;
  position: absolute;
  top: 100px;
}

@keyframes bounce {
  0%,100% {
    transform: translateY(0);
  }
  
  20% {
    background-color: black;
    transform: translateY(40px);
  }
  
  50% {
    background-color: red;
    transform: translateY(84px) rotateX(45deg);
  }
  70% {
    background-color: black;
    transform: translateY(40px);
  }
}
<div class = "ball">
</div>

<div class = "ground">
</div>

如您所见,我试图让球在接触地面时具有 "squeezed" 效果。我不得不使用 translateX84px 来保持球与地面的接触。我通过反复试验得到了 84px。有没有我可以用来计算偏移量的公式(即本例中的 4px)?

球以线速度下落,我试过使用ease-inease都没有用。我还尝试了 cubic-bezier.com 中的不同数字。我如何才能使它在弹回时由于重力加速度和减速度而随着时间增加速度?

如果你讨厌数学,请查看下面的解决方案 1

因为你在旋转元素 45deg 你会遇到这样的事情:

你要找的是绿线,你可以用下面的公式得到:

width/2 - X

在哪里

X = Width/2*cos(45deg)

所以你会有 Width/2*(1 - cos(45deg)) ~ Width/2*(1 - 0.707)

然后您可以调整百分比值来控制速度。作为旁注,您不应该使用初始值,而是使用较低的值以获得更逼真的动画:

body {
  margin: 0;
  padding: 0;
}

.ball {
  width: 20px;
  height: 20px;
  
  margin: 0 auto;
  
  border-radius: 50%;
  background-color: black;
  
  animation: bounce 2s infinite ease-in;
}

.ground {
  display: block;
  width: 100%;
  
  border-bottom: 1px solid black;
  position: absolute;
  top: 100px;
}

@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  
  30% {
    background-color: black;
    transform: translateY(80px);
  }
  
  40% {
    background-color: red;
    transform: translateY(calc(80px + 10px*(1 - 0.707))) rotateX(45deg);
  }
  
  50% {
    background-color: black;
    transform: translateY(80px);
  }
  100% {
    background-color: black;
    transform: translateY(50px);
  }
}
<div class = "ball">
</div>

<div class = "ground">
</div>

1 您也可以通过简单地将 transform-origin 更改为从底部旋转从而避免计算 space将从顶部减少:

body {
  margin: 0;
  padding: 0;
}

.ball {
  width: 20px;
  height: 20px;
  
  margin: 0 auto;
  
  border-radius: 50%;
  background-color: black;
  
  animation: bounce 2s infinite linear;
  transform-origin:bottom;
}

.ground {
  display: block;
  width: 100%;
  
  border-bottom: 1px solid black;
  position: absolute;
  top: 100px;
}

@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  
  30% {
    background-color: black;
    transform: translateY(78px);
  }
  
  40% {
    background-color: red;
    transform: translateY(80px) rotateX(45deg);
  }
  
  50% {
    background-color: black;
    transform: translateY(78px);
  }
  100% {
    background-color: black;
    transform: translateY(50px);
  }
}
<div class = "ball">
</div>

<div class = "ground">
</div>

如果你想要一个不真实的反弹效果,你可以试试这个:

body {
  margin: 0;
  padding: 0;
}

.ball {
  width: 20px;
  height: 20px;
  
  margin: 0 auto;
  
  border-radius: 50%;
  background-color: black;
  
  animation: bounce 2s infinite linear;
  transform-origin:bottom;
}

.ground {
  display: block;
  width: 100%;
  
  border-bottom: 1px solid black;
  position: absolute;
  top: 100px;
}

@keyframes bounce {
  0%,100% {
    transform: translateY(0);
  }
  
  35%,65% {
    background-color: black;
    transform: translateY(40px);
  }
  
  45%,55% {
    background-color: black;
    transform: translateY(75px);
  }
  
  50% {
    background-color: red;
    transform: translateY(80px) rotateX(45deg);
  }


}
<div class = "ball">
</div>

<div class = "ground">
</div>