有没有办法让动画计时功能应用于整个动画而不是每个关键帧?

发布于 2024-10-08 21:44:22 字数 812 浏览 4 评论 0原文

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

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

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

I'm a bit new to animation, so forgive me if I'm missing a huge concept here. I need to animate an arrow that is pointing to a point on a curve, let's just say it's a cubic curve for the sake of this post. The arrow moves along the curve's line, always pointing a few pixels below it.

So what I did, is I setup keyframes along the curve's line using 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;
     }
}

However, when I run this animation using -webkit-animation-timing-function: ease-in, it applies that easing to each individual keyframe, which is definitely not what I want. I want the easing to apply to the entire animation.

Is there a different way that I should be doing this? Is there some property to apply the easing to the entire sequence rather than each keyframe?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

£噩梦荏苒 2024-10-15 21:44:22

您无法对一系列关键帧应用缓动函数,因为您专门告诉对象在特定时间处于特定点。例如,如果您在一系列关键帧上应用缓入,那么在 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 支持沿着路径的动画,则不需要这些关键帧,并且将缓动仅应用于两个关键帧不会有任何问题。

You can't apply an easing function over a series of keyframes because you're specifically telling the object to be at a specific point at a specific time. If you applied, say, an ease-in over a series of keyframes, then at 25% the object would behind it's required "checkpoint", eventually accelerating until catching up at 100%.

If your points are more or less equidistant, you can apply:

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

and your animation will look more more less good, if a little robotic.

A more natural approach would be to accelerate, maintain speed, and then "brake":

 @-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;
 }
}

If webkit supported animations along a path you wouldn't need these keyframes and you would have no trouble applying the easing to only two keyframes.

ゃ懵逼小萝莉 2024-10-15 21:44:22

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

在这种情况下,您应该创建一个父 div 来应用移动动画,并创建一个子 div 来应用不透明度动画。不透明度动画应具有缓动曲线:线性,并且运动动画应具有最适合您的缓动函数。不过,我想重复 Duopixel 关于混合缓动曲线和固定检查点的说法 - 在这种情况下,您实际上不需要动画,只需两个 0%:100% 动画 - 一个用于父级,一个用于子级 div。

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

When you want different easing functions to apply to different aspects of an animation you should separate out your animations by nesting your content in two divs.

In this case, you should create a parent div to apply a movement animation to, and a child div to apply the opacity animation to. The opacity animation should have an easing curve: linear, and the movement animation should have whatever easing function looks best to you. However, I would repeat what Duopixel says about mixing easing curves and fixed checkpoints - in this case you shouldn't actually need animations, just two 0%:100% animations - one for the parent and one for the child div.

Having done a lot of CSS3 animation, I wrote this guide for our Sencha Animator product - it has some helpful general information on how to get complex animations working with CSS3 - even if you don't want to use the tool.

无声情话 2024-10-15 21:44:22

您无法使用 CSS 动画 来做到这一点,但是如果您不介意将其转换为 JavaScript,那么您可以使用 < a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API" rel="nofollow noreferrer">Web 动画 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 动画与 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>

You can't do it with CSS Animations but if you don't mind converting it to JavaScript then you can use Web Animations API instead.

The equivalent of such CSS Animation:

.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;
  }
}

would be this JS code:

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 }
);

However, you don't need to pass offset and easing parameters. If you omit them then the keyframes would be evenly spaced and you can define timing function with the easing option which will be applied to the whole animation.

    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" }
    );

Here is example that compares this two approaches (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>

穿透光 2024-10-15 21:44:22

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

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

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

Some reference love for you: http://www.w3.org/TR/css3-animations/

More specifically: http://www.w3.org/TR/css3-animations/#timing-functions-for-keyframes-

You may want to do animation stacking, such as move to one location, then another, then another in multiple keyframe animations rather than just one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文