【问题标题】:Is there a way for animation-timing-function to apply to the entire animation instead of each keyframe?有没有办法让动画计时功能应用于整个动画而不是每个关键帧?
【发布时间】:2011-05-30 21:43:36
【问题描述】:

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

所以我所做的是,我使用 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 运行此动画时,它会将缓动应用于每个单独的关键帧,这绝对不是我想要的。我希望将缓动应用于整个动画。

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

【问题讨论】:

    标签: css css-animations


    【解决方案1】:

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

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

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

    【讨论】:

    • 这适用于 webkit 吗?只需将 -webkit- 添加到属性中?
    • 这很接近,但计时功能只适用于最后一个关键帧...我希望计时功能适用于整个动画序列中的所有关键帧 -- 你能详细说明动画堆叠吗在 CSS3 中?
    【解决方案2】:

    您不能在一系列关键帧上应用缓动函数,因为您明确告诉对象在特定时间处于特定点。例如,如果您在一系列关键帧上应用了缓入,那么在 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 支持沿路径的动画,您将不需要这些关键帧,并且您可以轻松地将缓动应用于仅两个关键帧。

    【讨论】:

    • 是的,我认为这是一种解决方案,但它似乎过于复杂,试图找出沿路径的每个位置/时间可能非常耗时。但是,这是最好的答案。
    • 100% 使用animation 是否有理由? MDN 建议 ...永远不会使用在 100% 或关键帧上指定的动画计时功能。
    • 由于某种原因,使用这种技术,整个动画不会easy-out
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      你不能用 CSS Animations 来做,但如果你不介意将它转换成 JavaScript,那么你 can 使用 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 }
      );
      

      但是,您不需要传递offset and easing 参数。如果省略它们,则关键帧将均匀分布,您可以使用 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 动画与 Web 动画 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>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-13
        • 2013-07-17
        • 2014-07-23
        • 2016-07-15
        • 2015-07-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多