如何在CSS动画中制造重力效果?

9

我想要将一个元素动画化,仿佛你正在俯视地球。这个元素向你跳跃,达到顶点,然后再回落一点。侧面看轨迹就像这样:

     _
   /   \
  /     |
 |
 |

我无法通过关键帧动画实现真实效果。我的看起来像这样人造:

    /\
   /  \
  /
 /
/

CSS

@keyframes springIn {
    0% {
        transform: scale(0.0);
    }
    80% {
        transform: scale(1.2);
    }
    100% {
        transform: scale(1.0);
    }
}

.someElement {
    animation: springIn 1s linear 1s 1 forwards;
}

如何在动画中使用抛物线函数来实现重力效果?我曾考虑使用贝塞尔曲线,但CSS标准不允许使用[0,0]之外的点。


这可能是使用动画函数的轻微改进:http://jsfiddle.net/ExplosionPIlls/jyscZ/(仅适用于Chrome) - Explosion Pills
@ExplosionPills:你的 ease-out 不是应用于整个动画吗?我希望它在达到顶点时缓出,然后从顶点开始缓入下降。 - Pwner
3个回答

10

使用animation-timing-function在你的关键帧中,让两个过渡(上升后跟随下降)成为抛物线。


要正确地完成这个任务(即根据物理学),你需要首先确保“顶点”点的比例和时间相应正确。你的动画从0%到100%运行,而拱形的顶点(最大比例点)位于两者之间,我们称其为m%。比例从0(在0%处)开始,以1(在100%处)结束,并在m%处达到峰值,假设为s。然后使用一些基本数学知识,这两个变量之间的关系是:

m = 100 / (1 + sqrt(s-1))
或者
s = (100/m - 1)^2 + 1

要使峰值达到80%,您需要s= 17/16 = 1.0625。

或者,对于最大比例为s的情况,您需要将峰值提高至m = 69.0983 ...%。


现在,为了使过渡合理地呈抛物线形状,您需要使用抛物线animation-timing-function设置。当对象上升时,您想要有效地使用类似于ease-out的东西,当它开始下降时,您想要使用类似于ease-in的东西......但是与这两个关键字相关的三次贝塞尔曲线不完全是抛物线。

相反,请使用:

animation-timing-function: cubic-bezier(0.33333, 0.66667, 0.66667, 1)
为了动画中的“升起”部分:
animation-timing-function: cubic-bezier(0.33333, 0, 0.66667, 0.33333)

对于“fall”部分,这些曲线确实给出了精确的抛物线。(有关这些值的推导的数学细节,请参见此处;请注意,理想情况下,您应该使用1/3而不是0.33333和2/3而不是0.66667,但CSS不允许使用分数)。

将所有这些组合在一起,就可以得到以下CSS:


将所有这些组合在一起,就可以得到以下CSS:
.someElement { animation: springIn 1s linear 1s 1 none }

@keyframes springIn
{
  0% { transform: scale(0.0); animation-timing-function: cubic-bezier(0.33333, 0.66667, 0.66667, 1) }
  69.0983% { transform: scale(1.2); animation-timing-function: cubic-bezier(0.33333, 0, 0.66667, 0.33333) }
  100% { transform: scale(1.0) }
}

...如果我的计算是正确的,那应该会给你一个完美的抛物线动画轨迹!

(注意:我将animation-fill-mode更改为“none”,因为在动画结束后继续强制执行transform: scale(1.0)似乎并不必要。如果出于某种原因实际上需要,请将此值更改回“forwards”)。


1
Jon z,你的缩放比例有误,因为DIV是全页宽度,但其中只有左对齐的文本可见。此外,你的不透明度在峰值处回退到零,所以你永远看不到“下降”部分。我认为这更接近OP所想要的:http://jsfiddle.net/6La14v1c/4/。 - Doin

8
我认为你可以使用贝塞尔曲线来实现。
在你的情况下,可能是这样的:
-webkit-transition: all 500ms cubic-bezier(0.310, 0.440, 0.445, 1.650); 
-moz-transition: all 500ms cubic-bezier(0.310, 0.440, 0.445, 1.650); 
-ms-transition: all 500ms cubic-bezier(0.310, 0.440, 0.445, 1.650); 
-o-transition: all 500ms cubic-bezier(0.310, 0.440, 0.445, 1.650); 
transition: all 500ms cubic-bezier(0.310, 0.440, 0.445, 1.650); /* custom */

-webkit-transition-timing-function: cubic-bezier(0.310, 0.440, 0.445, 1.650); 
-moz-transition-timing-function: cubic-bezier(0.310, 0.440, 0.445, 1.650); 
-ms-transition-timing-function: cubic-bezier(0.310, 0.440, 0.445, 1.650); 
-o-transition-timing-function: cubic-bezier(0.310, 0.440, 0.445, 1.650); 
transition-timing-function: cubic-bezier(0.310, 0.440, 0.445, 1.650); /* custom */

我自己没有做过,可以参考这个链接:

CSS缓动动画工具

我在JSFiddle上做了一个示例

我添加了一个外部div来使悬停稳定:

<div class="container">
    <div class="moving"></div>
</div>

而CSS如下:

.moving {
    position: absolute; width: 200px; height: 150px; top: 50px;  left: 50px;
    background-color: green;
    -webkit-transition: all 5s cubic-bezier(0.310, 0.440, 0.445, 1.650); 
}

.container:hover .moving {
    zoom: 1.5;
}

编辑

这是一个贝塞尔曲线的图像(来自缓动动画工具页面),它展示了对象速度不需要保持恒定,可以是几乎抛物线形状。

bezier curve


我认为这个主要问题在于对象以恒定速度移动,这可能会使现实感稍微打折扣。 - Justin L.
啊,好的,我的错误;我没有看到定时函数是贝塞尔曲线,而不是位置。 - Justin L.
@JoJo 是的,支持非常薄弱。我只是提供了这些信息,因为OP谈到了这个问题,希望支持能够增强。Chrome 25.0.1364.172 m剪辑了一些属性的Bezier转换。缩放属性(请参见我提供的fiddle)运行良好。(至少在我看来是这样的)。顺便说一下,我没有说在fiddle中过渡是通过悬停div触发的。 - vals
超级贝塞尔曲线在iOS 6上运行良好,这也是我需要它工作的唯一平台。 - Pwner
上面的曲线并不是真正的抛物线;它看起来不是“完全正确”的。您可以使用三次贝塞尔曲线生成实际的抛物线轨迹-请参见下面的解决方案。对于完整的抛物线跳跃和全部回落,或者如果浏览器剪切到[0,1],那么您只需要使用2个关键帧,每个关键帧为半个抛物线。 - Doin
显示剩余3条评论

1
Adobe提供了一个不错的示例, 它只使用标准的ease-in/ease-out时间函数。即使它可能不完全“物理”(即不是抛物线),但对于许多情况来说仍然足够好。如果您向下滚动到Physics is your friend部分,页面上有一个演示。
div {
    width:140px;
    height:140px;
    border-radius: 70px;
    background:red;
    position:relative;
    animation: jump 1s infinite;
}

@keyframes jump {
    0% {top: 0;animation-timing-function: ease-in;}
    50% {top: 140px;height: 140px;animation-timing-function: ease-out;}
    55% {top: 160px; height: 120px;border-radius: 70px / 60px;animation-timing-function: ease-in;}
    65% {top: 120px; height: 140px;border-radius: 70px;animation-timing-function: ease-out;}
    95% {top: 0;animation-timing-function: ease-in;}
    100% {top: 0;animation-timing-function: ease-in;}
}

来源:http://www.adobe.com/inspire/2013/04/animating-interactive-experiences-css.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接