28

我对动画有点陌生,所以如果我在这里错过了一个巨大的概念,请原谅我。我需要为指向曲线上一个点的箭头设置动画,为了这篇文章,我们假设它是一条三次曲线。箭头沿着曲线的线移动,始终指向它下方的几个像素。

所以我所做的是,我使用 CSS3 沿曲线设置关键帧:

 @-webkit-keyframes ftch {
     0% {
         opacity: 0;
         left: -10px;
         bottom: 12px;
     }
     
    25% {
        opacity: 0.25;
        left: 56.5px;
        bottom: -7px;
     }
     
     50% {
        opacity: 0.5;         
        left: 143px;
        bottom: -20px;
     }
     
     75% {
        opacity: 0.75;
        left: 209.5px;
        bottom: -24.5px;
     }
     
     100% {
         opacity: 1;
         left: 266px;
         bottom: -26px;
     }
}

但是,当我使用 -webkit-animation-timing-function:ease-in 运行此动画时,它会将缓动应用于每个单独的关键帧,这绝对不是我想要的。我希望缓动适用于整个动画。

我应该这样做有不同的方式吗?是否有一些属性可以将缓动应用于整个序列而不是每个关键帧?

4

4 回答 4

17

您不能在一系列关键帧上应用缓动函数,因为您专门告诉对象在特定时间处于特定点。例如,如果您在一系列关键帧上应用了缓入,那么在 25% 时,对象将在其后面需要“检查点”,最终加速直到赶上 100%。

如果您的积分或多或少等距,您可以申请:

.animatedobject {
  -webkit-animation-timing-function: linear;
}

如果有点机器人的话,你的动画看起来会更好。

更自然的方法是加速、保持速度,然后“刹车”:

 @-webkit-keyframes ftch {
 0% {
     opacity: 0;
     left: -10px;
     bottom: 12px;
    -webkit-animation-timing-function: ease-in;
 }

25% {
    opacity: 0.25;
    left: 56.5px;
    bottom: -7px;
    -webkit-animation-timing-function: linear;
 }

 50% {
    opacity: 0.5;         
    left: 143px;
    bottom: -20px;
    -webkit-animation-timing-function: linear;
 }

 75% {
    opacity: 0.75;
    left: 209.5px;
    bottom: -24.5px;
    -webkit-animation-timing-function: linear;
 }

 100% {
     opacity: 1;
     left: 266px;
     bottom: -26px;
    -webkit-animation-timing-function: ease-out;
 }
}

如果 webkit 支持沿路径的动画,那么您将不需要这些关键帧,并且您可以轻松地将缓动应用于仅两个关键帧。

于 2010-12-27T05:35:38.707 回答
2

当您希望将不同的缓动函数应用于动画的不同方面时,您应该通过将内容嵌套在两个 div 中来分离动画。

在这种情况下,您应该创建一个父 div 来应用移动动画,以及一个子 div 来应用不透明动画。不透明动画应该有一个缓动曲线:线性,并且运动动画应该有任何你认为最好的缓动函数。但是,我会重复 Duopixel 所说的关于混合缓动曲线和固定检查点的内容 - 在这种情况下,您实际上不需要动画,只需要两个 0%:100% 动画 - 一个用于父 div,一个用于子 div。

在完成了很多 CSS3 动画之后,我为我们的 Sencha Animator 产品编写了本指南——它提供了一些关于如何使用 CSS3 获得复杂动画的有用的一般信息——即使您不想使用该工具。

于 2010-12-27T23:44:04.767 回答
1

一些参考爱你:http ://www.w3.org/TR/css3-animations/

更具体地说:http ://www.w3.org/TR/css3-animations/#timing-functions-for-keyframes-

您可能想要进行动画堆叠,例如移动到一个位置,然后是另一个位置,然后是多个关键帧动画中的另一个位置,而不仅仅是一个。

于 2010-12-26T18:03:50.147 回答
1

你不能用CSS Animations来做,但如果你不介意将它转换成 JavaScript,那么你可以使用Web Animations API来代替。

相当于这样的 CSS 动画:

.css-animation-ease {
  animation-name: move-animation;
  animation-duration: 3s;
}

@keyframes move-animation {
  25% {
    transform: translate(100px, 0);
  }
  50% {
    transform: translate(100px, 100px);
    background-color: green;
  }
  75% {
    transform: translate(0, 100px);
  }
  100% {
    transform: translate(0, 200px);
    background-color: blue;
  }
}

将是这个 JS 代码:

box.animate(
  [
    { easing: "ease" },
    { transform: "translate(100px, 0)", offset: 0.25, easing: "ease" },
    { transform: "translate(100px, 100px)", backgroundColor: "green", 
      offset: 0.5, easing: "ease" },
    { transform: "translate(0, 100px)", offset: 0.75, easing: "ease" },
    { transform: "translate(0, 200px)", backgroundColor: "blue", easing: "ease" },
  ],
  { duration: 3000 }
);

但是,您不需要传递offseteasing参数。如果省略它们,则关键帧将均匀分布,您可以使用easing将应用于整个动画的选项定义计时功能。

    box.animate(
        [
            {},
            { transform: "translate(100px, 0)" },
            { transform: "translate(100px, 100px)", backgroundColor: "green" },
            { transform: "translate(0, 100px)" },
            { transform: "translate(0, 200px)", backgroundColor: "blue" },
        ],
        { duration: 3000, easing: "ease" }
    );

这是比较这两种方法的示例(CSS Animation vs Web Animations API)

document.getElementById("animateAll").addEventListener("click", () => {
  for (const btn of document.querySelectorAll(".examples button")) {
    btn.click();
  }
});

document
  .getElementById("cssAnimationLinearBtn")
  .addEventListener("click", () => {
    const box = document.getElementById("cssAnimationLinear");
    box.classList.add("css-animation-linear");
    box.addEventListener("animationend", () => {
      box.classList.remove("css-animation-linear");
    });
  });

document.getElementById("cssAnimationEaseBtn").addEventListener("click", () => {
  const box = document.getElementById("cssAnimationEase");
  box.classList.add("css-animation-ease");
  box.addEventListener("animationend", () => {
    box.classList.remove("css-animation-ease");
  });
});

document
  .getElementById("webAnimationLinearBtn")
  .addEventListener("click", () => {
    const box = document.getElementById("webAnimationLinear");
    box.animate(
      [
        {},
        { transform: "translate(100px, 0)" },
        { transform: "translate(100px, 100px)", backgroundColor: "green" },
        { transform: "translate(0, 100px)" },
        { transform: "translate(0, 200px)", backgroundColor: "blue" },
      ],
      { duration: 3000 }
    );
  });

document
  .getElementById("webAnimationEaseOffsetBtn")
  .addEventListener("click", () => {
    const box = document.getElementById("webAnimationEaseOffset");
    box.animate(
      [
        { easing: "ease" },
        { transform: "translate(100px, 0)", offset: 0.25, easing: "ease" },
        {
          transform: "translate(100px, 100px)",
          backgroundColor: "green",
          offset: 0.5,
          easing: "ease",
        },
        { transform: "translate(0, 100px)", offset: 0.75, easing: "ease" },
        {
          transform: "translate(0, 200px)",
          backgroundColor: "blue",
          easing: "ease",
        },
      ],
      { duration: 3000 }
    );
  });

document.getElementById("webAnimationEaseBtn").addEventListener("click", () => {
  const box = document.getElementById("webAnimationEase");
  box.animate(
    [
      {},
      { transform: "translate(100px, 0)" },
      { transform: "translate(100px, 100px)", backgroundColor: "green" },
      { transform: "translate(0, 100px)" },
      { transform: "translate(0, 200px)", backgroundColor: "blue" },
    ],
    { duration: 3000, easing: "ease" }
  );
});
.examples {
  display: grid;
  grid-template-columns: repeat(5, 130px);
}

.box {
  width: 30px;
  height: 30px;
  background-color: red;
}

.box.css-animation-linear {
  animation: move-animation 3s linear 1;
}

.box.css-animation-ease {
  animation-name: move-animation;
  animation-duration: 3s;
}

@keyframes move-animation {
  25% {
    transform: translate(100px, 0);
  }
  50% {
    transform: translate(100px, 100px);
    background-color: green;
  }
  75% {
    transform: translate(0, 100px);
  }
  100% {
    transform: translate(0, 200px);
    background-color: blue;
  }
}
<button id="animateAll">Animate all</button>
<div class="examples">
    <div>
        <span style="color:brown">CSS Animation API (linear)</span>
        <button id="cssAnimationLinearBtn">Animate</button>
        <div id="cssAnimationLinear" class="box"></div>
    </div>
    <div>
        <span style="color:green">CSS Animation API (ease)</span>
        
        <button id="cssAnimationEaseBtn">Animate</button>
        <div id="cssAnimationEase" class="box"></div>
    </div>
    <div>
        <span style="color:brown">Web Animation API (linear)</span>
        <button id="webAnimationLinearBtn">Animate</button>
        <div id="webAnimationLinear" class="box"></div>
    </div>
    <div>
        <span style="color:green">Web Animation API (ease, offset)</span>
        <button id="webAnimationEaseOffsetBtn">Animate</button>
        <div id="webAnimationEaseOffset" class="box"></div>
    </div>
    <div>
        <strong>Web Animation API (ease)</strong>
        <button id="webAnimationEaseBtn">Animate</button>
        <div id="webAnimationEase" class="box"></div>
    </div>
</div>

于 2021-02-08T18:15:40.060 回答