CSS 之 帧动画(Keyframe Animation)

news2024/11/29 2:31:49

一、简介

​ CSS 制作 Web 动画有两种方式: 帧动画(Keyframe Animation)和过渡动画(Transition Animation)。在不同的业务场景中,我们应该选择不同的动画方式,通常来说:对于交互元素,会使用过渡动画,而对于连续的装饰性元素,则应该使用帧动画。

​ 本文章将会仔细讲解帧动画的相关知识,让你对其有一个较为全面的了解。

二、帧动画

1、基本概念

​ 帧动画允许你通过指定 CSS 属性在不同时间点上的行为来创建动画效果,这些时间点被称为关键帧,所以又被称为关键帧动画。帧动画需要通过@keyframes来创建。

​ 关键帧动画的主要思想是在多个不同时间点的CSS代码块之间进行插值计算,这个插值计算由浏览器自动完成的,它会根据@keyframes中定义的多个代码块中的样式变化,自动创建样式变化的中间状态,从而样式能够平滑的变化。

​ 一个帧动画主要由两个关键部分组成:创建帧动画和使用帧动画。

2、创建帧动画
动画名称:

​ 在使用@keyframes创建关键帧动画时,会在其后面跟随一个自定义标识符,表示当前动画的名称,该名称可在其所在作用域内通过animation-name使用。但要注意的是:不要使用CSS的关键词来命名动画,例如autowidth等等,这可能会导致动画失效。

@keyframes 动画名称 {...}

/* 正确命名 */
@keyframes fadeOut {...}

/* 错误命名 */
@keyframes auto {...}   

​ 动画名称标识符是严格区分大小写的,fadeOutfadeout是两个不同的名称。而且如果多个动画使用相同的名称,则通过动画名称调用动画时,将以定义顺序中的最后一个动画为准。

/* 严格区分大小写 */
@keyframes fadeOut {...}
/* 两者并不相同 */
@keyframes fadeout {...}

/* 当命名重复时 以最后定义的为准 */
@keyframes fadeOut {...}
动画关键帧:

@keyframes内部没有时间的概念,它只有一个百分比完成的概念,n%表示的是动画完成的百分比,可以在0%~100%之间的任何一个位置定义,一个百分比表示一个关键帧,可以定义任意数量的关键帧。浏览器会在关键帧之间进行插值计算,使帧与帧之间的样式平滑的进行变化。

@keyframes 动画名称 {
  /* 动画关键帧 */
  0% {
    /* 样式 */
  }
  /* 。。。 */
  100% {
    /* 样式 */
  }
}

​ 除了使用n%之外,还有两个关键字fromto可以使用,两者分别等同于0%100%

@keyframes fadeOut {
    0% {
        opacity: 1;
    }
    
    100% {
        opacity: 0;
    }
}
/* 等同于 */
@keyframes fadeOut {
    from {
        opacity: 1;
    }
    
    to {
        opacity: 0;
    }
}

​ 在 @keyframes 规则中的关键帧顺序并不重要,因为浏览器将按照百分比值的顺序播放,而不是按照它们在代码中出现的先后顺序播放。而且如果定义的关键帧百分比出现了重复的情况,则在执行时,会将重复的关键帧百分比进行合并,如果存在重复的属性,则属性值以最后定义的为准。

@keyframes move {
    0% {
      background: red;
      transform: translateX(0);
    }
    50% {
      background: yellow;
      transform: translateX(200px);
    }
    100% {
      background: red;
      transform: translateX(0);
    }
    50% {
      transform: translateX(50px);
      opacity: 0.5;
    }
}
/* 等同于 */
@keyframes move {
    0% {
      background: red;
      transform: translateX(0);
    }
    50% {
      background: yellow;
      transform: translateX(50px);
      opacity: 0.5;
    }
    100% {
      background: red;
      transform: translateX(0);
    }
}

​ 如果没有指定 0% / from 关键帧,以及100% / to 关键帧,则浏览器会以动画绑定元素的初始样式为内容,构造 0% / from 关键帧和100% / to 关键帧。

.d {
  width: 100px;
  height: 100px;
  background: red;
  animation: move 2s infinite;
} 
@keyframes move {
  /* 未定义 0%和100% 关键帧 */
  50% {
    background: yellow;
    transform: translateX(200px);
    width: 200px;
  }
}
/* 等同于 */
@keyframes move {
  0% {
     width: 100px;
     height: 100px;
     background: red;
  }
  50% {
    background: yellow;
    transform: translateX(200px);
    width: 200px;
  }
  100% {
     width: 100px;
     height: 100px;
     background: red;
  }
}
关键帧中的!important

​ 关键帧中的!important将会被忽略,并不会抬高样式属性值的权重。因为在元素动画过程中,关键帧中声明的样式不在级联的上下文中,但本身的权重已经超过所有的普通权重样式,所以再无法通过!important来提高权重。

​ 但是动画所绑定的元素上的样式如果使用了!important,则该样式不会被动画中定义的样式属性值所影响,因为该权重超过了动画样式的权重。

@keyframes move {
    0% {
      background: red;
      transform: translateX(0);
    }
    50% {
      background: yellow;
      transform: translateX(50px);
    }
    100% {
      background: red;
      transform: translateX(0);
    }
}

.d {
    width: 100px;
    height: 100px;
    /* 该样式使用了important提高权重 不会被动画关键帧中的样式所影响 */
    background: red !important;
    animation: move 2s infinite;
}
关键帧中的CSS自定义属性:

​ CSS的自定义属性是指以--开头的声明的变量,其可以通过var(--属性名)的形式,将自定义属性的属性值在作用域范围内的任何一个属性上使用:

.d {
    /* 定义自定义属性 */
    --w: 20px;
    /* 使用自定义属性 等同于 width: 20px; */
    width: var(--w);
    height: 20px;
    background: red;
    /* 使用自定义属性 等同于 border: 20px solid #ccc; */
    border: var(--w) solid #ccc;
}

​ 自定义属性可以在关键帧中使用,可以正常渲染,但是如果在关键帧中修改自定义属性的值,且元素样式中使用了该自定义属性,则浏览器无法对其进行插值计算,也就无法实现平滑的动画效果。主要原因为CSS 自定义属性的值对于浏览器来说相当于一个字符串,字符串的变化属于是不连贯的属性,无法进行插值计算。

@keyframes changeW {
  50% {
    --w: 40px;
  }
}
.d {
   --w: 20px;
   width: var(--w);
   height: 20px;
   background: red;
   border: var(--w) solid #ccc;
   animation: changeW 2s infinite;
}

​ 该问题可以通过CSS的@property特性来解决,但该特性属于实验性技术,有浏览器兼容性问题。因此此处就不展开叙述了,更多具体可查看: @property。

关键帧合并:

​ 如果@keyframes 中定义的多个关键帧存在样式属性重复,则可以将多个关键帧进行合并定义,减少代码重复。再将各个关键帧中不重复的样式属性进行单独定义,浏览器会将定义两次的关键帧内的样书进行合并,如果存在重复的属性,则属性值以最后定义的为准。

@keyframes move {
  /* 将多个关键帧中的重复样式属性合并定义 */
   0%,
   100% {
     background: red;
     transform: translateX(0);
     width: 100px;
   }
   50% {
     background: yellow;
     transform: translateX(200px);
     width: 200px;
   }
  /* 不重复的样式属性再进行单独定义 */
   100% {
     /* 该关键帧的定义位于后面 所以属性值优先级高 */
     width: 150px;
   }
}
/* 等同于 */
@keyframes move {
   0%{
     background: red;
     transform: translateX(0);
     width: 100px;
   }
   50% {
     background: yellow;
     transform: translateX(200px);
     width: 200px;
   }
   100% {
     background: red;
     transform: translateX(0);
     width: 150px;
   }
}
3、使用帧动画

@keyframes 仅仅是定义了在所在作用域内全局都可以使用的关键帧动画,定义好了动画的过程,但是其并不能自动应用。还需要通过CSS的animation属性来显式的指定关键帧动画应用的元素,以及一系列相关的动画属性。

.test-div {
  /* 使用动画 */
  animation: fadeOut 500ms linear;
}
animation-name:

​ 该属性用于指定引用@keyframs动画的名称,必须严格遵守大小写,fadeOutfadeout是两个不同的名称。

animation-name:fadeOut;

​ 该属性可以设置多个动画名称,属性值之间通过,进行分隔,表示同时引用多个动画。

animation-name:fadeOut, moveTo;
animation-duration:

​ 该属性用于指定动画完成一个周期所需要的时间,值必须为非负数,单位为sms,默认为0。该时间定义了**@keyframes** 中的的时间轴,关键帧百分比值(n%)对应的时间节点是相对于该时间轴来计算的。

animation-duration: 2s;
animation-duration: 200ms;

​ 如果该属性值为0,则动画效果是否可见取决于animation-fill-mode属性的值,而animation-fill-mode的表现效果又受到animaiton-direction属性的影响。具体情况分为下面四种:

  • 如果animation-fill-mode: none;,无论animaiton-direction设置什么值,则动画无任何视觉效果。
  • 如果animation-fill-mode: forwards/both;,且animaiton-direction: normal/alternate;,则动画会直接显示最后一帧的样式效果。
  • 如果animation-fill-mode: forwards/both;,且animaiton-direction: reverse/alternate-reverse;,则动画会直接显示第一帧的样式效果。
  • 如果animation-fill-mode: backwards;,无论animaiton-direction设置什么值,则动画都会直接显示第一帧的样式效果。

​ 该属性可以设置多个运动时间,属性值之间通过,进行分隔,设置的多个属性值会按照顺序映射到对应的animation-name中的动画上。如果该属性值的数量等于animation-name属性值的数量,则两者一一对应;如果该属性值的数量小于animation-name属性值的数量,则多余的动画以重复该属性的属性值,使属性值与动画一一对应;如果该属性值的数量大于animation-name属性值的数量,则多余的属性值会被忽略。

.animated {
    animation-name: translate, rotate, scale;
    animation-duration: 1s;
    /* 属性值数量小于动画的数量 最终等同于 */
    animation-duration: 1s, 1s, 1s;
}

.animated {
    animation-name: translate, rotate, scale;
    animation-duration: 1s, 2s;
    /* 属性值数量小于动画的数量 最终等同于 */
    animation-duration: 1s, 2s, 1s;
}

.animated {
    animation-name: translate, rotate, scale;
    /* 属性值数量等于动画的数量 一一对应 */
    animation-duration: 1s, 2s, 3s; 
}

.animated {
    animation-name: translate, rotate, scale;
    animation-duration: 1s, 2s, 3s, 4s;
    /* 属性值数量大于动画的数量 最终等同于 */
    animation-duration: 1s, 2s, 3s; 
    /* 动画时间 4s 没有相应的关键帧动画,将会被忽略 */
}

animation-timing-function:

​ 该属性用于指定动画执行时的速度曲线,属性值有:linearease(默认值)、ease-inease-outease-in-out ,以及steps()cubic-bezier()(贝塞尔曲线函数)。

animation-timing-function:linear;
  • linear表示匀速运动,速度曲线是一条直线。

  • ease(默认值)表示慢-快-慢,初期速度很慢,然后先逐渐加速,再快速减速,最终缓慢结束。加速过程较缓,减速过程较快。

  • ease-out表示减速运动,先快后慢,初期速度很快,然后逐渐减速,最终缓慢结束。

  • ease-in表示加速运动,先慢后快,初期速度很慢,然后逐渐加速,最终快速结束。

  • ease-in-out表示慢-快-慢,初期速度慢,然后逐渐加速,中期速度最快,然后逐渐减速,最终缓慢结束。加速过程和减速过程相当。

  • linear() 函数定义了一个分段线性函数,可以在其各个点之间线性插值,从而允许你模拟出更复杂的动画效果,比如弹跳和弹簧等效果。JS或SVG可以通过linear曲线生成器 生成相应的曲线参数。

  • steps()函数定义了分步运动,其效果相当于逐步执行过渡动画,类似于帧动画,接受两个参数,第一个参数指定的是步数,第二个参数指定的是方向。第二个参数值可以是 jump-startjump-endjump-nonejump-bothstartend(默认值) ,其中 startjump-start 表现行为一样,同样的 endjump-end 表现行为一样。函数还有两个预定义的关键字:step-startstep-end。前者等同于 steps(1, start),而后者等同于 steps(1, end)

    jump-start表示第一步动画在开始时发生;jump-end 表示最后一步动画在结束时发生;jump-both 表示在 0% 和 100% 处均出现跳跃,相当于在动画过程中加上一步;表示两端均无跳跃,而是在 0% 处和 100% 处将值各保持 1/n 的时长。更多内容可以查看:easing-function

  • cubic-bezier()用于定义贝塞尔曲线,贝塞尔曲线由 P0、P1、P2 和 P3 四个点进行定义。P0 和 P3 是曲线的起点和终点,在 CSS 中,这两个点是固定的,因为坐标是成比例。P0 为 (0, 0),代表初始时间和初始状态,P3 为 (1, 1),代表最终时间和最终状态。其余的中间点 P1(x1,y1)、P2(x2,y2) 是可以动态改变的两个点,对应 cubic-bezier(x1,y1,x2,y2) 中的四个参数,通过改变 P1、P2 两点的坐标值来动态生成的贝塞尔曲线表示动画中的速度变化。

    ​ 具体的贝塞尔曲线很难直接书写出来,我们可以通过贝塞尔曲线生成器,来获取对应的曲线值。或者可以通过浏览器调试工具对速度曲线进行调整。

    ​ 在固定y的情况下,x越大运动越慢,在固定x情况下,y越大运动越快。y如果是负数,则元素会变小,y’如果大于1,则会变大,但最终还会恢复为1。

    在这里插入图片描述

animation-delay:

​ 该属性用于指定动画初始开始执行前需要延迟等待的时间,单位为sms,默认为0。如果动画会执行多次,也只会在初次执行时进行延迟等待,在后续执行时,不会再进行延迟等待。

animation-delay: 2s;

​ 该属性设置的属性值通常为正值,但如果属性值为负数,则浏览器会按照该负数的绝对值时间,跳转到该时间对应的动画节点处开始执行动画,类似于动画从中间节点开始执行。其实负值中的负号相当于一个信号,告诉浏览器将这个值视为偏移而不是延迟,偏移到该时间对应的动画节点处开始执行动画。

​ 如果指定的偏移时间(animtion-delay)大于动画单次迭代的持续时间,则需要进一步考虑是否有足够的迭代次数,使动画总的执行时间大于偏移时间。如果大于等于,则初始会偏移跳转到对应的时间节点处开始执行动画;如果小于,则动画不会有执行过程,而且直接跳转到动画的最终结束状态。

<style>
@keyframes move {
  0% {
    background: red;
    transform: translateX(20px);
  }
  50% {
    background: yellow;
    transform: translateX(200px);
  }
  100% {
    background: red;
    transform: translateX(0);
  }
}
.d {
    width: 180px;
    height: 100px;
    margin-bottom: 10px;
    background: red;
    /* 执行时间5秒 匀速 保留结束和开始样式 执行1次 */
    animation: move 5s linear both 1;
    /* 延迟时间为0 */
    animation-delay: 0;
}
.d1 {
    /* 延迟时间为正数 正常延迟 */
    animation-delay: 3s;
}
.d2 {
    /* 延迟时间为负数 且绝对值小于动画的总执行周期 延迟变为偏移 从中间1.5s节点开始执行 */
    animation-delay: -1.5s;
}
.d3 {
    /* 延迟时间为负数 且绝对值大于动画的总执行周期 直接展示结束状态 */
    animation-delay: -6s;
}
</style>

<body>
  <div class="d"></div>
  <div class="d d1"></div>
  <div class="d d2"></div>
  <div class="d d3"></div>
</body>

页面效果:

在这里插入图片描述

​ 该属性还可以设置多个动画延迟时间,属性值之间通过,进行分隔,设置的多个属性值会按照顺序映射到对应的animation-name中的动画上。如果该属性值的数量等于animation-name属性值的数量,则两者一一对应;如果该属性值的数量小于animation-name属性值的数量,则多余的动画以重复该属性的属性值,使属性值与动画一一对应;如果该属性值的数量大于animation-name属性值的数量,则多余的属性值会被忽略。

.element {
    animation-name: color, translate, scale, rotate, opacity;
    animation-delay: .5s;
    /* 属性值数量相等 最终等同于 */
    animation-delay: .5s, .5s, .5s, .5s, .5s;
}

.element {
    animation-name: color, translate, scale, rotate, opacity;
    animation-delay: .5s, 1s;
    /* 属性值数量小于动画的数量 最终等同于 */
    animation-delay: .5s, 1s, .5s, 1s, .5s;
}

.element {
    animation-name: color, translate, scale, rotate, opacity;
    animation-delay: .5s, 1s, 1.5s, 2s, 2.5s;
    /* 属性值数量等于动画的数量 一一对应 */
    animation-delay: .5s, 1s, 1.5s, 2s, 2.5s;
}

.element {
    animation-name: color, translate, scale, rotate, opacity;
    animation-delay: .5s, 1s, 1.5s, 2s, 2.5s, 3s;
    /* 属性值数量大于动画的数量 最终等同于 */
    animation-delay: .5s, 1s, 1.5s, 2s, 2.5s; /* 多余的 3s 将会被忽略 */
}
animation-iteration-count:

​ 该属性用于指定动画播放的次数,属性值可以为正整数或infinite(循环无限播放),默认为1,表示动画只执行一次。

animation-iteration-count: infinite;
animation-direction:

​ 该属性用于指定动画的执行方向,其属性值有四种:

  • normal(默认值):表示动画正向执行,在每次执行中,都是从0%/from执行到100%/to。如果动画执行多次(animation-iteration-count),则一次执行结束后,下一次执行时会立即回到起点(0%/from),并重新从起点执行。
  • reverse:表示动画反向执行,在每次执行中,都是从100%/to执行到0%/from。如果动画执行多次(animation-iteration-count),则一次执行结束后,下一次执行时会立即回到动画起点(100%/to),并重新从起点执行。
  • altermate:表示动画正反交替执行。如果动画执行多次(animation-iteration-count),则奇数次执行按正向执行,而偶数次迭代按反向执行。
  • alternate-reverse:表示动画反向交替执行。如果动画执行多次(animation-iteration-count),则奇数次执行按反向执行,而偶数次迭代按正向执行。

​ 总结一下:normalreverse 两者表现行为恰好相反;alternatealternate-reverse 两者表现行为恰好相反;alternate 同时具备 normalreverse 两者表现特征。

animation-direction: altermate;

​ 当该属性值为reverse时,动画的时间函数效果也会被反转,因为设置的时间函数是相对于正向执行的。例如:ease-in 时间函数将变为 ease-out

​ 该属性还会影响到animation-fill-mode属性的最终效果,具体可以看下面的animation-fill-mode章节。

animation-play-state:

​ 该属性用于指定动画是否执行,默认值为running,表示正在执行。可以设置属性值为paused,表示暂停动画,动画会暂停执行,并保留当前时间节点的样式状态。如果再次设置属性值为running,则会从当前状态继续执行。

// 暂停动画
animation-play-state: paused;
// 运行动画
animation-play-state: running;

​ 该属性通常与:hover:focus以及通过Js变更类名等操作结合使用,实现动画的暂停与播放。

@keyframes spin {
    to {
        rotate: 360deg;
    }
}

.animated {
    /* 默认正常执行动画 */
    animation: spin 2s linear infinite;
}
.animated:hover {
  	/* hover时暂停动画 离开hover状态时继续执行动画 */
    animation-play-state: paused;
}

​ 还有一种常见的应用场景是:在页面中存在大量的动画时,这些动画可能会消耗大量的 CPU 和 GPU 资源。即使用户当前并未查看页面上的某些动画,它们仍然在后台运行,可能导致性能下降。可以通过暂停那些不在视窗或容器可视区中的动画,只播放位于可视区域内的动画的方式,从而减轻系统负担,提高页面整体性能。

animation-fill-mode:

​ 该属性用于指定动画的填充模式,即在动画执行开始前/结束后,@keyframes 中声明的关键帧样式是否对目标元素有效。

​ 该属性有四个属性值:

  • none(默认值),表示在动画执行结束后@keyframes 中所有样式都无效,展示元素本身的样式。
  • forwards(向前取样式),表示在动画结束后,将会应用动画结束时最后一帧的样式,也就是正常情况下@keyframes100%/to关键帧的样式。该关键帧位于动画结束后的前面,所以是向前取样式。
  • backwards(向后取样式),表示在动画开始前(包括animation-delay时间),将会应用动画开始时第一帧的样式,也就是正常情况下@keyframes0%/from关键帧的样式。该关键帧位于动画开始前的后面,所以是向后取样式。
  • both,表示同时遵循forwardsbackwards的规则,在开始前应用动画开始时的样式,在结束后应用动画结束时的样式。
animation-fill-mode: both;

​ 该属性会被animation-direction属性和animation-iteration-count属性影响到,在使用时要注意。

​ 如果animation-direction属性值为reversealternate-reverse,动画反向播放,则此时动画第一帧的样式对应100%/to,动画的最后一帧对应0%/from。此时该属性设置属性值为forwards/backwards/both,具体的样式效果就会与正常情况相反。

animation-iteration-count属性也是类似的道理,其效果会改变动画的最后一帧对应的样式,从而会影响到animation-fill-mode属性的具体效果。例如下面的例子:动画的最后一个关键帧是 0% ,因为动画运行了两次,第一次迭代是从 0%100% ,第二次迭代从 100%0%

@keyframes ani {
    0% {
        translate: -300px;
    }
    100% {
        translate: 300px;
    }
}
.animated {
    animation: ani5s linear forwards;
    animation-fill-mode: forwards;
		animation-direction: alternate;
		animation-iteration-count: 2;
}

animation-direction属性和animation-iteration-count属性与最后一帧的关系,如下图所示:

在这里插入图片描述

animation-composition:

​ 该属性用于指定动画合成的逻辑,即动画关键帧中的样式属性(效果值)与元素本身的同一样式属性(基础值)或者多个动画元素之前的相同样式属性的复合操作。

  • replace(替换,默认值):表示将效果值覆盖基础值,页面样式为效果值。或者是在多个动画之间,最后一个动画将完全替换之前的动画效果,也就是只有最后一个动画效果会起作用。
  • add(叠加):表示将效果值添加到基础值之后,其效果相当于在基础值的的样式基础上继续叠加效果值的样式。或者是在多个动画之间,将多个动画的效果会叠加在一起,一起影响属性的最终效果。例如,如果一个动画元素向右移动 30px ,而另一个动画使元素向左移动 20px ,使用 add 复合操作之后,元素将向右移动 10px
  • accumulate(累计):表示将效果值与基础值累计相加。如果属性值为数值类型,则最终效果为两者相加后的样式。或者是在多个动画之间,将属性值累计相加。例如元素默认有一个 filter 属性的值为 blur(5px) , 动画1的 0% 位置有一个 blur(10px) ,动画2的 0% 位置有一个 blur(20px) ,设置该属性后,0% 关键帧的 filter 属性的复合值是 blur(35px)
@keyframes move {
  0% {
    transform: translateX(0px);
    width: 200px;
  }
  50% {
    transform: translateX(200px);
    width: 400px;
  }
  100% {
    transform: translateX(0);
    width: 200px;
  }
}
.d {
   width: 180px;
   height: 100px;
   background: red;
   animation: move 5s infinite;
   /* 设置效果为相加 则初始0% 和 结束100%时 的width的实际效果为380px 50%时的实际效果为580px */
   animation-composition: accumulate;
}

​ 该属性通常不在CSS中使用,都是在JavaScript中使用,结合Web动画API使用:

element.animate([
  { transform: 'translateX(0px)' },
  { transform: 'translateX(100px)' }
], {
  duration: 1000,
  composite: 'add'
});

​ 更多相关内容可查看:animation-composition。

其他属性:

​ 除了上面那些标准动画属性之外,还有一些实验性动画属性,此处就不展开讲述了,感兴趣的可以自行查看:

  • animation-range:该属性用于设置动画附件范围沿其时间线的开始和结束位置,即动画沿时间线的开始和结束位置。
  • animation-range-start:该属性用于设置动画的附件范围沿其时间线的开始位置,即动画沿时间线的开始位置。
  • animation-range-end:该属性用于设置动画附件范围沿其时间线的结束位置,即动画沿时间线的结束位置。
  • animation-timeline:该属性用于指定控制 CSS 动画进度的时间线。
animation属性简写:

​ 除animation-composition之外,其他animation的相关属性都可以简写到一起,简写属性如下:

animation: 动画名称 持续时间 运动曲线 延迟等待时间 执行次数 执行方向 填充模式 执行状态
animation: animation-name animation-duration animation-timing-function animation-delay animation-iteration-count animation-direction animation-fill-mode animation-play-state;

​ 例如:

animation: move 2s linear 1s infinite alternate forwards running;

​ 简写属性中<time>类型的属性值的顺序很重要,其中第一个可以被解析时间的值会被分配给animation-duration,再次出现的第二个值,才会分配给animation-delay。而其余属性值的顺序就不是那么重要了。

animation同时应用多个动画:

​ 如果要给同一个元素指定多个动画,则只需要在animation中,通过,分隔设置多个动画的相关动画属性即可。

animation: move 2s linear 1s infinite alternate forwards, bear 2s linear·;

​ 不同的动画之间的属性互不干扰,但具体应用到动画元素上的样式可能会有冲突覆盖。例如,一个动画试图将元素向左移动,而另一个动画同时试图将元素向右移动。此时的具体动画效果就取决于animation-composition属性的值。

​ 为了避免这些问题,要尽量减少多个动画同时作用于同一个元素的情况,可以通过分层动画的形式,拆分动画。例如:

<style>
@keyframes xAxis {
    50% {
        animation-timing-function: ease-in;
         translate:450px 0;
    }
}
@keyframes yAxis {
    50% {
      animation-timing-function: ease-out;
      translate: 0 -450px;
    }
}  
.xAxis {
    animation: xAxis 2.5s infinite linear;
}
.yAxis {
    animation: yAxis 2.5s infinite linear;
}
</style>

<div class="dot xAxis">
    <span class="yAxis"></span>
</div>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1670556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库管理-第187期 23ai:怎么用SQL创建图(20240510)

数据库管理187期 2024-05-10 数据库管理-第187期 23ai:怎么用SQL创建图&#xff08;20240510&#xff09;1 安装PGX1.1 数据库配置对应用户1.2 使用RPM包安装Graph Server1.3 安装Oracle Graph Client1.4 访问PGX页面 2 SQL Property Graph2.1 创建SQL属性图2.2 关于点和边图元…

k8s 使用Docker和Containerd对比分析

目录 k8s 使用Docker和Containerd对比分析 互动1&#xff1a;docker build构建的镜像和containerd镜像通用吗&#xff1f; 互动2&#xff1a;k8s1.24之前版本和1.24及1.24之后版本区别&#xff1f; k8s 使用Docker和Containerd对比分析 如果你使用Docker作为K8S容器运行时的…

NASA数据集——非洲加蓬上空的回波能量波形、高程数据和地理标记图像V001版本

数据英文名称 AfriSAR LVIS L1B Geolocated Return Energy Waveforms V001 AfriSAR LVIS L2 Geolocated Surface Elevation Product V001 AfriSAR LVIS L1A Geotagged Images V001 简介 该数据集包含非洲加蓬上空的回波能量波形数据。测量数据由美国国家航空航天局的陆地、…

《一“企”谈》∣企企通走进『鹏辉能源』,探索百亿储能上市企业如何实现供应链数字化转型

随着运营模式的升级和市场竞争的加剧&#xff0c;采购数字化已成为企业提升竞争力的关键。通过整合人工智能、大数据、云计算和物联网等先进技术&#xff0c;采购流程正逐步实现智能化、协同化和绿色化&#xff0c;大幅提升采购效率和决策质量。 广州鹏辉能源科技股份有限公司&…

STM: SpatioTemporal and Motion Encoding for Action Recognition 论文阅读

STM: SpatioTemporal and Motion Encoding for Action Recognition 论文阅读 Abstract1. Introduction2. Related Works3. Approach3.1. Channel-wise SpatioTemporal Module3.2. Channel-wise Motion Module3.3. STM Network 4. Experiments5. Conclusion 文章信息&#xff1a…

vin查询接口如何对接

vin查询接口是VIN车辆识别代码查询接口的简称&#xff0c;也叫vin查询车辆信息接口、车架号查询接口&#xff0c;指的是输入车辆VIN识别码&#xff08;车架号&#xff09;&#xff0c;返回车辆相关信息&#xff0c;如车辆品牌、车型、油耗、车身形式、排量等。那么vin查询接口如…

数据治理平台有哪些核心功能?十款热门数据治理平台盘点

数据治理是管理企业数据资产全过程中的决策、监督和执行控制&#xff0c;旨在引导和影响组织内所有其他数据管理活动&#xff0c;核心目标是确保数据按照既定的管理制度和行业最佳实践得到妥善管理。不论企业是否设有正式的数据治理职位&#xff0c;那些确立了正式数据治理流程…

高德地图:标点-连线-自定义图标-文字提示的使用

目录 下面是使用高德地图进行标点连线的使用&#xff1a; 1.定义一个装载地图的容器&#xff0c;并定义进行标点和连线的数据 2.在组件的mounted钩子函数中初始化地图&#xff0c;给地图添加点击事件监听器。 3.使用高德地图的Polyline类来绘制连接线。 这是上面代码的效果…

人工智能生成图像的兴起:区分事实与虚构

人工智能生成图像的兴起&#xff1a;区分事实与虚构 概述 在人工智能 (AI) 已融入我们日常生活的时代&#xff0c;人工智能生成图像的快速发展引发了人们对数字内容真实性的担忧。最近&#xff0c;人工智能生成的图像甚至欺骗了最敏锐的眼睛&#xff0c;这引发了人们对批判性…

Shell生成支持x264的ffmpeg安卓全平台so

安卓 FFmpeg系列 第一章 Ubuntu生成ffmpeg安卓全平台so 第二章 Windows生成ffmpeg安卓全平台so 第三章 生成支持x264的ffmpeg安卓全平台so&#xff08;本章&#xff09; 文章目录 安卓 FFmpeg系列前言一、实现步骤1、下载x264源码2、交叉编译生成.a3、加入x264配置4、编译ffmp…

数字水印 | Python 基于离散小波变换 DWT 的图像水印嵌入(下)

&#x1f34d;原文&#xff1a; 基于 dwt (离散小波变换) 实现彩色图像水印嵌入部分_2.0 &#x1f34d;写在前面&#xff1a; 本文在原文的基础上进行了代码补全。 正文 修改了尺寸变换导致的图像失真问题&#xff0c;同时简化了部分代码。 效果确实很好&#x1f609; 1 通道…

15W 3KVAC隔离 宽电压输入 AC/DC 电源模块——TP15AL系列

TP15AL系列产品是一款小体积裸板式电源,该系列电源输出功率为15W,具有低漏电流小于0.35mA,隔离耐压高达3KV等特点。产品安全可靠&#xff0c;EMC性能好&#xff0c;该系列产品广泛应用于智能家居、充电桩、安防、物联、工控等行业中&#xff0c;如应用于电磁兼容比较恶劣的环境…

Kerberos修改协议为TCP

部署前 修改模板/home/cloud-setup/deploy-forklift/mids/forklift-basic/kde/v1.0/impl/plays/roles/krb5-client/templates/krb5.conf.j2 添加如下参数 udp_preference_limit 1 部署后 界面修改 添加如下参数&#xff0c;并勾选下发配置按钮&#xff0c;重启刷新服务

Linux-04

账号管理 添加账号 useradd 选项 用户名 useradd -m dai删除帐号 userdel 选项 用户名 userdel -r dai修改帐号 usermod 选项 用户名usermod -d /home/user dai &#xff08;修改位置&#xff09;切换帐号 su username su dai退出账号 exit $表示普通用户 #表示超级用户&#…

源代码防泄密的关键点:烧录管控

源代码作为企业技术核心的一部分&#xff0c;其保密性和安全性显得尤为重要。然而&#xff0c;随着开源文化的发展&#xff0c;以及开发过程中不可避免的与外界交流&#xff0c;源代码防泄密工作面临着前所未有的挑战。特别是在烧录过程中&#xff0c;由于涉及到硬件层面的操作…

PyWebIO,用 Python 写网站

在Python的世界里&#xff0c;PyWebIO是一个简单而强大的库&#xff0c;它能让你的Python脚本快速拥有一个交互式的网页界面。想象一下&#xff0c;你不需要懂得前端开发&#xff0c;就能创建出用户友好的网页应用&#xff0c;这是多么酷的一件事&#xff01;今天&#xff0c;我…

排序-快速排序(Quick Sort)

快排的简介 快速排序&#xff08;Quick Sort&#xff09;是一种高效的排序算法&#xff0c;采用分治法的策略&#xff0c;其基本思想是选择一个基准元素&#xff0c;通过一趟排序将待排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据都比另外一部分的所有数据要…

aop获取方法运行时间

Slf4j Component Aspect//aop类 public class TimeAspect {/*Around 环绕通知 用ProceedingJoinPoint Before 前置通知 用JoinPoint&#xff08;是ProceedingJoinPoint的父类型&#xff09;&#xff0c;用它可以获得方法执行的相关信息&#xff0c;如目标类名&#xff0c;方法…

我是如何免费抵御一个多月的 DDos/CC 攻击的?

今天明月给大家详细分享一下我的博客是如何免费抵御了长达一个多月的 DDos/CC 攻击的&#xff0c;在【现在 DDos/CC 攻击门槛低的可怕&#xff01;】一文里明月就说过现在 DDos/CC 攻击几乎是没有门槛的&#xff0c;任何一个老鼠屎在群里看到你的博客都可以轻松便捷的发动一次 …

ADOP带你了解:800G OSFP光收发器:演进发布

引言 随着云计算、大数据和人工智能等技术的不断进步&#xff0c;对数据中心的带宽和处理能力要求也在不断提高。在这样的背景下&#xff0c;800G OSFP光收发器的问世&#xff0c;为我们提供了更高速度和更高效率的数据传输解决方案。 800G OSFP光收发器演进路线 路线 1&…