如何改进纯 CSS3 弹跳球动画

How to improve a pure CSS3 bouncing ball animation

作为一个更大的混合应用程序项目的一部分,我需要让用户通过点击编号为 0 到 9 的弹跳球来 select 一组四个数字。我不想笨拙带有物理引擎的应用程序,因此我选择使用纯 CSS3 动画。我的努力如下所示

body,html
{
 margin:0;
 padding:0;
 background-color:black;
}
#stage{position:relative;}
.ball 
{
 position:absolute;
 width:7vw;
 height:7vw;
 border-radius:50%;
 display:flex;
 justify-content:center;
 align-content:center;
 align-items:center;
 margin:0;
 padding:0;
}

@keyframes bounce 
{ 
 0% {transform:translateY(0);}
 95% {transform:translateY(86vh);}
 100% {transform:translateY(86vh);}
}

#ballZero
{
 background: #f45342;
 margin-left:1em;
 animation:bounce 3s;
 animation-direction:alternate;
 animation-timing-function:ease;
 animation-iteration-count:infinite;
}

#ballOne
{
 background-color:lime;
 margin-left:calc(2em + 7vw);
 animation:bounce 2.7s;
 animation-direction:alternate;
 animation-timing-function:ease;
 animation-iteration-count:infinite;
}

#ballTwo
{
 background-color:aqua;
 margin-left:calc(3em + 14vw);
 animation:bounce 3.2s;
 animation-direction:alternate;
 animation-timing-function:ease;
 animation-iteration-count:infinite;
}
<!DOCTYPE html>
<html>
<head>
 <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
 <link rel='stylesheet' href='matter.css'/>
  <style>
   body,html{margin:0;padding:0;font-family:arial;}
   #stage
   {
    height:100vh;
    width:100vw;
   }
  </style>
</head>
<body>
 <div id='stage'>
 <div class="ball" id='ballZero'>0</div>
 <div class='ball' id='ballOne'>1</div>
 <div class='ball' id='ballTwo'>2</div>
 </div>
 </body>
 
</html>

虽然这行得通,但结果并不顺利,而且我认识到 CSS 动画远不是我的强项。我怎样才能改进这个动画,使效果看起来更逼真——请记住,在真实情况下我需要 10 个球?尽管有100% {transform:translateY(86vh);},但为什么球一碰到底部就不会反弹?

body,html
{
 margin:0;
 padding:0;
 background-color:black;
}
#stage{position:relative;}
.ball 
{
 position:absolute;
 width:7vw;
 height:7vw;
 border-radius:50%;
 display:flex;
 justify-content:center;
 align-content:center;
 align-items:center;
 margin:0;
 padding:0;
}

@keyframes bounce 
{ 
 0% {transform:translateY(0);}
 100% {transform:translateY(86vh);}
}

#ballZero
{
 background: #f45342;
 margin-left:1em;
 animation:bounce 3s;
 animation-direction:alternate;
 animation-timing-function:ease-in;
 animation-iteration-count:infinite;
}

#ballOne
{
 background-color:lime;
 margin-left:calc(2em + 7vw);
 animation:bounce 2.7s;
 animation-direction:alternate;
 animation-timing-function:ease-in;
 animation-iteration-count:infinite;
}

#ballTwo
{
 background-color:aqua;
 margin-left:calc(3em + 14vw);
 animation:bounce 3.2s;
 animation-direction:alternate;
 animation-timing-function:ease-in;
 animation-iteration-count:infinite;
}
<!DOCTYPE html>
<html>
<head>
 <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
 <link rel='stylesheet' href='matter.css'/>
  <style>
   body,html{margin:0;padding:0;font-family:arial;}
   #stage
   {
    height:100vh;
    width:100vw;
   }
  </style>
</head>
<body>
 <div id='stage'>
 <div class="ball" id='ballZero'>0</div>
 <div class='ball' id='ballOne'>1</div>
 <div class='ball' id='ballTwo'>2</div>
 </div>
 </body>
 
</html>

如果我们为向上和向下飞行添加稍微不同的计时功能,我们会得到更多的弹跳效果 - 当然是在地面弹跳上。

@keyframes bounce 
{ 
 0% {transform:translateY(0); animation-timing-function: ease-in;}
 60% {transform:translateY(86vh); animation-timing-function: ease-out;}
 100% {transform:translateY(0); animation-timing-function: ease-in;}
}

尝试使用三次贝塞尔定时函数,我们可能会得到更好的结果——尽管这似乎是一个实验领域。 这是应用上述函数的结果:

 body,html
{
 margin:0;
 padding:0;
 background-color:black;
}
#stage{position:relative;}
.ball 
{
 position:absolute;
 width:7vw;
 height:7vw;
 border-radius:50%;
 display:flex;
 justify-content:center;
 align-content:center;
 align-items:center;
 margin:0;
 padding:0;
}

@keyframes bounce 
{ 
 0% {transform:translateY(0); animation-timing-function: ease-in;}
 60% {transform:translateY(86vh); animation-timing-function: ease-out;}
 100% {transform:translateY(0); animation-timing-function: ease-in;}
}

#ballZero
{
 background: #f45342;
 margin-left:1em;
 animation:bounce 3s;
 animation-direction:alternate;
 animation-timing-function:ease;
 animation-iteration-count:infinite;
}

#ballOne
{
 background-color:lime;
 margin-left:calc(2em + 7vw);
 animation:bounce 2.7s;
 animation-direction:alternate;
 animation-timing-function:ease;
 animation-iteration-count:infinite;
}

#ballTwo
{
 background-color:aqua;
 margin-left:calc(3em + 14vw);
 animation:bounce 3.2s;
 animation-direction:alternate;
 animation-timing-function:ease;
 animation-iteration-count:infinite;
} 
 body,html{margin:0;padding:0;font-family:arial;}
   #stage
   {
    height:100vh;
    width:100vw;
   }
<div id='stage'>
  <div class="ball" id='ballZero'>0</div>
  <div class='ball' id='ballOne'>1</div>
  <div class='ball' id='ballTwo'>2</div>
</div>