使用秒而不是百分比来表达CSS3 @keyframe

时间:2018-03-28 22:53:54

标签: javascript html css html5 css3

我在2016年1月学习了CSS3 @keyframes语法,两年后,我现在发现自己在我的工作中使用@keyframes动画(比CSS3过渡更复杂,比基于javascript的动画)。

我真正想念的一件事是能够在几秒钟内表达@keyframes而不是百分比。是否有任何黑客可以实现这一目标?

我知道我可以使用以下100s黑客循环彩虹色,每3秒钟一个周期:



div {
    width: 120px;
    height: 120px;
    background-color: violet;
    animation: myAnimation 100s;
}

@keyframes myAnimation {
    0% {background-color: red;}
    3% {background-color: orange;}
    6% {background-color: yellow;}
    9% {background-color: green;}
   12% {background-color: cyan;}
   15% {background-color: blue;}
   18% {background-color: violet;}
  100% {background-color: violet;}
}

<div></div>
&#13;
&#13;
&#13;

但这意味着动画在(有效地)完成之后的另一个82秒仍在运行(虽然不知不觉)。除了其他问题之外,这使得多次迭代无法实现。

我真正想写的是:

@keyframes myAnimation {

  0s {background-color: red;}
  3s {background-color: orange;}
  6s {background-color: yellow;}
  9s {background-color: green;}
 12s {background-color: cyan;}
 15s {background-color: blue;}
 18s {background-color: violet;}
}

有没有比我在上面的代码框中详述的方法更好的方法?

使用多个元素的示例

事后我意识到,上面的例子可能使上面的例子过于简单,因为它涉及动画单个元素,而我的问题最初是出于希望动画多个元素相互同步的动画。

所以,这是一个稍微详细的例子,显示的设置更接近于首先引起我问题的设置:

&#13;
&#13;
div {
display: inline-block;
width: 48px;
height: 48px;
margin-right: 6px;
}

div:nth-of-type(1) {
background-color: red;
}

div:nth-of-type(2) {
background-color: orange;
animation: myAnimationOrange 100s;
}

div:nth-of-type(3) {
background-color: yellow;
animation: myAnimationYellow 100s;
}

div:nth-of-type(4) {
background-color: green;
animation: myAnimationGreen 100s;
}

div:nth-of-type(5) {
background-color: cyan;
animation: myAnimationCyan 100s;
}

div:nth-of-type(6) {
background-color: violet;
animation: myAnimationViolet 100s;
}

@keyframes myAnimationOrange {
    0% {background-color: white;}
    1% {background-color: white;}
    2% {background-color: orange;}
  100% {background-color: orange;}
}

@keyframes myAnimationYellow {
    0% {background-color: white;}
    2% {background-color: white;}
    3% {background-color: yellow;}
  100% {background-color: yellow;}
}

@keyframes myAnimationGreen {
    0% {background-color: white;}
    3% {background-color: white;}
    4% {background-color: green;}
  100% {background-color: green;}
}

@keyframes myAnimationCyan {
    0% {background-color: white;}
    4% {background-color: white;}
    5% {background-color: cyan;}
  100% {background-color: cyan;}
}

@keyframes myAnimationViolet {
    0% {background-color: white;}
    5% {background-color: white;}
    6% {background-color: violet;}
  100% {background-color: violet;}
}
&#13;
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
&#13;
&#13;
&#13;

4 个答案:

答案 0 :(得分:3)

不要忘记您可以在同一元素上运行多个动画,并且可以单独设置durationdelay和所有其他animation-...规则。

例如,您可以将所有关键帧拆分为单键@keyframes规则 然后,当他们开始并将它们链接起来时,它很容易控制。

&#13;
&#13;
div {
    width: 120px;
    height: 120px;
    background-color: violet;
    animation-fill-mode: forwards;
    animation-name: orange, yellow, green, cyan, blue, violet;
    animation-delay: 0s, 3s, 6s, 9s, 12s, 15s, 18s;
    animation-duration: 3s; /* same for all */
}

@keyframes orange {
    to { background-color: orange; }
}
@keyframes yellow {
    to { background-color: yellow; }
}
@keyframes green {
    to { background-color: green; }
}
@keyframes cyan {
    to { background-color: cyan; }
}
@keyframes blue {
    to { background-color: blue; }
}
@keyframes violet {
    to { background-color: violet; }
}
&#13;
<div></div>
&#13;
&#13;
&#13;

关于问题编辑

在这种情况下,您甚至不需要在同一元素上组合多个动画,只需相应地设置animation-delay

&#13;
&#13;
div {
 /* same for all */
    width: 60px;
    height: 60px;
    display: inline-block;
    background-color: white;
    animation-fill-mode: forwards;
    animation-duration: 3s;
}
div:nth-of-type(1) {
  animation-name: orange;
  animation-delay: 0s;
}
div:nth-of-type(2) {
  animation-name: yellow;
  animation-delay: 3s;
}
div:nth-of-type(3) {
  animation-name: green;
  animation-delay: 6s;
}
div:nth-of-type(4) {
  animation-name: cyan;
  animation-delay: 9s;
}
div:nth-of-type(5) {
  animation-name: blue;
  animation-delay: 12s;
}
div:nth-of-type(6) {
  animation-name: violet;
  animation-delay: 15s;
}

@keyframes orange {
    to { background-color: orange; }
}
@keyframes yellow {
    to { background-color: yellow; }
}
@keyframes green {
    to { background-color: green; }
}
@keyframes cyan {
    to { background-color: cyan; }
}
@keyframes blue {
    to { background-color: blue; }
}
@keyframes violet {
    to { background-color: violet; }
}
&#13;
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
&#13;
&#13;
&#13;

但如果你想将两者结合在一起,那也很可能:

&#13;
&#13;
div {
 /* same for all */
    width: 60px;
    height: 60px;
    display: inline-block;
    background-color: white;
    animation-fill-mode: forwards;
    animation-duration: 3s;
}
div:nth-of-type(1) {
  animation-name: orange, yellow, green, cyan, blue, violet;
  animation-delay: 0s, 3s, 6s, 9s, 12s, 15s;
}
div:nth-of-type(2) {
  animation-name: yellow, green, cyan, blue, violet;
  animation-delay: 3s, 6s, 9s, 12s, 15s;
}
div:nth-of-type(3) {
  animation-name: green, cyan, blue, violet;
  animation-delay: 6s, 9s, 12s, 15s;
}
div:nth-of-type(4) {
  animation-name: cyan, blue, violet;
  animation-delay: 9s, 12s, 15s;
}
div:nth-of-type(5) {
  animation-name: blue, violet;
  animation-delay: 12s, 15s;
}
div:nth-of-type(6) {
  animation-name: violet;
  animation-delay: 15s;
}

@keyframes orange {
    to { background-color: orange; }
}
@keyframes yellow {
    to { background-color: yellow; }
}
@keyframes green {
    to { background-color: green; }
}
@keyframes cyan {
    to { background-color: cyan; }
}
@keyframes blue {
    to { background-color: blue; }
}
@keyframes violet {
    to { background-color: violet; }
}
&#13;
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

目前不是。文档明确说明您只能使用百分比:

https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes

据推测,其背后的原因是动画的持续时间没有在关键帧中定义,而是在animation-duration属性中定义,因此插值器必须能够将关键帧拉伸到任何持续时间。 / p>

答案 2 :(得分:1)

SCSS Mixins将延迟转换为百分比

示例https://codepen.io/jakob-e/pen/vVXeOe

SCSS

body {
    @include animation-timeline {
        animation-iteration-count: infinite;
        animation-fill-mode: forwards;

        @include tween(0s, (background-color: violet));        
        @include tween(3s, (background-color: red));
        @include tween(3s, (background-color: orange));
        @include tween(3s, (background-color: yellow));
        @include tween(3s, (background-color: green));
        @include tween(3s, (background-color: cyan));
        @include tween(3s, (background-color: blue));
        @include tween(3s, (background-color: violet));
    }
}

CSS输出

body {
    animation-iteration-count: infinite;
    animation-fill-mode: forwards;
    animation-name: u33q65otn;
    animation-duration: 21s;
}

@keyframes u33q65otn {
    0% { background-color: violet; }
    14.2857142857% { background-color: red; }
    28.5714285714% { background-color: orange; }
    42.8571428571% { background-color: yellow; }
    57.1428571429% { background-color: green; }
    71.4285714286% { background-color: cyan; }
    85.7142857143% { background-color: blue; }
    100% { background-color: violet; }
}

mixins

//  global context flags using wierd ☠️ names to minimize 
//  chance of naming conflicts with other scss variables
$☠️--animation-timeline-duration: null;
$☠️--animation-timeline-tweens  : null;

//  mixin to create an animation context for nested tweens
//  used to calculate the total duration of the animation
//  converting each tween delay into percentages 
@mixin animation-timeline($name: unique-id()) {

    //  global context flag to sum up duration
    $☠️--animation-timeline-duration: 0s !global;    

    //  global context map to hold animation tweens
    $☠️--animation-timeline-tweens  : () !global;

    //  mixin content (the included tweens)
    @content;

    //  animation name and duration 
    //  note! if no name is provided a unique id will be used
    //  this allows you to create one-time-use animations without
    //  having to deal with animation naming conflicts :-)     
    animation-name:     $name;
    animation-duration: $☠️--animation-timeline-duration;

    //  create keyframes
    @keyframes #{$name} {
        //  loop through the included tweens 
        @each $time, $props in $☠️--animation-timeline-tweens {
            //  calculate percentage based on total duration
            #{percentage($time/$☠️--animation-timeline-duration)}{ 
                //  print out the tween properties
                @each $prop, $value in $props {
                    #{$prop}:$value;
                }
            }
        }
    }

    //  reset global context flags
    $☠️--animation-timeline-duration: null !global;
    $☠️--animation-timeline-tweens  : null !global;
}


//  mixin to create tweens based on a delay and a map
//  containing the the tween properties*
//
//  * using a map is not optimal – but for now you are not 
//  able to save @content to variables :( 
//  
@mixin tween($delay: 0s, $props: null){
    //  only do stuff if we are in a animation-timeline context
    @if $☠️--animation-timeline-tweens {
        //  increment the total animation by the the tween delay 
        $☠️--animation-timeline-duration: $☠️--animation-timeline-duration + $delay !global;
        //  save current duration and tween props to the global tween map
        $☠️--animation-timeline-tweens: map-merge($☠️--animation-timeline-tweens,  ($☠️--animation-timeline-duration: $props)) !global;
    }
}

答案 3 :(得分:-1)

你的黑客有点尴尬。为什么不直接使用18s作为动画持续时间,并逐步循环显示百分比?

&#13;
&#13;
div {
   width: 120px;
   height: 120px;
   background-color: violet;
   animation: myAnimation 18s;
}

@keyframes myAnimation {
   0% {background-color: red;}
   18% {background-color: orange;}
   37% {background-color: yellow;}
   55% {background-color: green;}
   71% {background-color: cyan;}
   88% {background-color: blue;}
   100% {background-color: violet;}
}
&#13;
<div></div>
&#13;
&#13;
&#13;

我不认为你应该能够在@keyframes间隔内使用秒数。我们已经在CSS中使用其他所有内容的秒数。 See how it works here