如何为CSS动画添加物理效果?

Yan*_*era 14 html javascript css css3

我只是在使用css进行一些加载,我希望它们有一个真实的行为,我正在尝试animation-timing-function: cubic-bezier(1, 0, 1, 1),看起来很好但不像我想的那样真实,起初因为我不知道cubic-bezier参数如何真正起作用,我找到了这个网站,只是和他们一起玩,直到我得到了一些不错的东西.

总结一下,如何在动画中添加真实的物理行为?

请仅使用CSS,如果不可能,欢迎使用JS解决方案.

这里有一个FIDDLE示例.

只是一个指导的建议

像定义的常量物理变量更少或者SCSS,或者你可以添加到函数中的值和物理行为的总和甚至可能已经模拟某些行为的mixins,我不知道简单而且只有CSS.

Thx提前

小智 11

您可以使用仅限CSS,但是您将花费大量时间来计算Bezier,关键帧位置,比例等的数字,并且最重要的是:您的布局略有变化,"重力",尺寸,距离你必须开始"全面"(至少在上面的部分).

CSS动画很不错,但是使用一些JavaScript代码可以获得更好的结果,更不用说如果你需要改变一些东西就有更多的灵活性 -

  • 定义球的矢量
  • 定义任意重力
  • 计算向量和反弹
  • 使用变换将结果值绑定到DOM元素(与位置相比给出更平滑的结果).
  • 动画使用requestAnimationFrame哪个同步监视并提供与CSS动画一样平滑的动画.

例

这个例子显示了基本的,不包括阴影,但这留给了读者的练习.

var div = document.querySelector("div"),
    v = {x: 2.3, y: 1},       // some vector
    pos = {x: 100, y: 20},    // some position
    g = 0.5,                  // some gravity
    absorption = 0.7,         // friction/absorption
    bottom = 150,             // floor collision
    frames = 0;               // to reset animation (for demo)

// main calculation of the animation using a particle and a vector
function calc() {
  pos.x += v.x;               // update position with vector
  pos.y += v.y;
  v.y += g;                   // update vector with gravity
  if (pos.y > bottom) {       // hit da floor, bounce
    pos.y = bottom;           // force position = max bottom
    v.y = -v.y * absorption;  // reduce power with absorption
  }
  if (pos.x < 0 || pos.x > 620) v.x = -v.x;
}

// animate
(function loop() {
  calc();
  move(div, pos);
 
  if (++frames > 220) {       // tweak, use other techniques - just to reset bounce
    frames = 0; pos.y = 20;
  }
  requestAnimationFrame(loop)
})();

function move(el, p) {
  el.style.transform = el.style.webkitTransform = "translate("+p.x+"px,"+p.y+"px)";
}
Run Code Online (Sandbox Code Playgroud)
div {
  width:20px;
  height:20px;
  background:rgb(0, 135, 222);
  border-radius:50%;
  position:fixed;
}
Run Code Online (Sandbox Code Playgroud)
<div></div>
Run Code Online (Sandbox Code Playgroud)

如果你想要更准确地反弹地板,你可以使用实际位置的差异来反映它:

if (pos.y > bottom) {
    var diff = pos.y - bottom;
    pos.y = bottom - diff;
    ...
Run Code Online (Sandbox Code Playgroud)

如果您需要多个元素,只需创建一个实例化对象,该对象嵌入对元素的引用以进行动画处理,计算等.

如果您现在想要更改方向,起点,重力等,您只需更新相应的值,并且在重放时一切顺利.

生成CSS关键帧的示例中间步骤

您可以修改上面的代码来处理CSS动画的数字.

使用帧数并标准化序列范围,通过计算帧来运行计算.然后提取每个值,比如说每10帧以及每次反弹,最后将数字格式化为关键帧.

理想情况下,您将始终包括顶部和底部位置 - 您可以通过监视矢量的y值(符号)的方向来检测这一点,此处未显示.

这将作为生成CSS规则的中间步骤,我们稍后将使用它:

var v = {x: 2.3, y: 1},       // some vector
    pos = {x: 100, y: 20},    // some position
    g = 0.5,                  // some gravity
    absorption = 0.7,         // friction/absorption
    bottom = 150,             // floor collision
    frames = 0,               // to reset animation (for demo)
    maxFrames = 220,          // so we can normalize
    step = 10,                // grab every nth + bounce
    heights = [],             // collect in an array as step 1
    css = "";                 // build CSS animation

// calc CSS-frames
for(var i = 0; i <= maxFrames; i++) {
  var t = i / maxFrames;
  pos.x += v.x;               // update position with vector
  pos.y += v.y;
  v.y += g;                   // update vector with gravity

  if (pos.y > bottom) {
    pos.y = bottom;
    v.y = -v.y * absorption;
    heights.push({pst: t * 100, y: pos.y});
  }  
  else if (!(i % step)) {heights.push({pst: t * 100, y: pos.y})}  
}

// step 2: format height-array into CSS
css += "@keyframes demo {\n";
for(i = 0; i < heights.length; i++) {
  var e = heights[i];
  css += "  " + e.pst.toFixed(3) + "% {transform: translateY(" + e.y.toFixed(3) + "px)}\n";
}
css += "}";

document.write("<pre>" + css + "</pre>");
Run Code Online (Sandbox Code Playgroud)

如果我们从中获取结果并将其用作最终页面的CSS,我们得到这个结果(对不起,只有在这个演示中没有前缀的版本):

(你当然必须调整和微调这个,但你会得到要点.)

div  {
  animation: demo 3s linear infinite;
  width:20px;
  height:20px;
  border-radius:50%;
  background:rgb(0, 148, 243);
  position:fixed;
  left:100px;
}

@keyframes demo {
  0.000% {transform: translateY(21.000px)}
  4.545% {transform: translateY(58.500px)}
  9.091% {transform: translateY(146.000px)}
  9.545% {transform: translateY(150.000px)}
  13.636% {transform: translateY(92.400px)}
  18.182% {transform: translateY(75.900px)}
  22.727% {transform: translateY(109.400px)}
  25.455% {transform: translateY(150.000px)}
  27.273% {transform: translateY(127.520px)}
  31.818% {transform: translateY(106.320px)}
  36.364% {transform: translateY(135.120px)}
  37.727% {transform: translateY(150.000px)}
  40.909% {transform: translateY(125.563px)}
  45.455% {transform: translateY(133.153px)}
  47.273% {transform: translateY(150.000px)}
  50.000% {transform: translateY(134.362px)}
  54.545% {transform: translateY(148.299px)}
  55.000% {transform: translateY(150.000px)}
  59.091% {transform: translateY(138.745px)}
  61.818% {transform: translateY(150.000px)}
  63.636% {transform: translateY(141.102px)}
  67.727% {transform: translateY(150.000px)}
  68.182% {transform: translateY(147.532px)}
  72.727% {transform: translateY(150.000px)}
  77.273% {transform: translateY(150.000px)}
  81.818% {transform: translateY(150.000px)}
  86.364% {transform: translateY(150.000px)}
  90.909% {transform: translateY(150.000px)}
  95.455% {transform: translateY(150.000px)}
  100.000% {transform: translateY(150.000px)}
}
Run Code Online (Sandbox Code Playgroud)
<div></div>
Run Code Online (Sandbox Code Playgroud)

我个人会推荐JavaScript支持,因为它对这些类型的动画更准确,并且如上所述,它可以轻松地采用新的要求.