1、css动画介绍及用法
CSS 动画用于实现元素从一个 CSS 样式配置转换到另一个 CSS 样式配置。
动画包括两个部分: 描述动画的样式规则和用于指定动画开始、结束以及中间点样式的关键帧(即规则与关键帧)
div {
animation: change 3s;
}
@keyframes change {
0% {
color: #f00;
}
100% {
color: #000;
}
}
animation: move 1s
部分就是动画的第一部分,用于描述动画的各个规则;@keyframes move {}
部分就是动画的第二部分,用于指定动画开始、结束以及中间点样式的关键帧;
一个 CSS 动画一定要由上述两部分组成。
2、css动画语法
创建动画序列,需要使用 animation 属性或其子属性,该属性允许配置动画时间、时长以及其他动画细节,但该属性不能配置动画的实际表现,动画的实际表现是由 @keyframes 规则实现
animation 的子属性有:
- animation-name:指定由 @keyframes 描述的关键帧名称。
- animation-duration:设置动画一个周期的时长。
- animation-delay:设置延时,即从元素加载完成之后到动画序列开始执行的这段时间。
- animation-direction:设置动画在每次运行完后是反向运行还是重新回到开始位置重复运行。
- animation-iteration-count:设置动画重复次数, 可以指定 infinite 无限次重复动画
- animation-play-state:允许暂停和恢复动画。
- animation-timing-function:设置动画速度, 即通过建立加速度曲线,设置动画在关键帧之间是如何变化。
- animation-fill-mode:指定动画执行前后如何为目标元素应用样式
- @keyframes 规则,当然,一个动画想要运行,还应该包括 @keyframes 规则,在内部设定动画关键帧
其中,对于一个动画:
- 必须项:
animation-name
、animation-duration
和@keyframes
规则 - 非必须项:
animation-delay
、animation-direction
、animation-iteration-count
、animation-play-state
、animation-timing-function
、animation-fill-mode
,当然不是说它们不重要,只是不设置时,它们都有默认值
3、animation-name / animation-duration 详解
通过 animation-name
,CSS 引擎将会找到对应的 @keyframes 规则。
而 animation-duration
设置动画一个周期的时长
4、animation-delay
就比较有意思了,它可以设置动画延时,即从元素加载完成之后到动画序列开始执行的这段时间。
特别注意 animation-delay 可以为负值
关于 animation-delay
,最有意思的技巧在于,它可以是负数。也就是说,虽然属性名是动画延迟时间,但是运用了负数之后,动画可以提前进行。
假设我们要实现这样一个 loading 动画效果,有几种思路:
- 初始 3 个球的位置就是间隔 120°,同时开始旋转,但是这样代码量会稍微多一点
- 另外一种思路,同一个动画,3 个元素的其中两个延迟整个动画的 1/3,2/3 时间出发
方案 2 的核心伪代码如下:
.item:nth-child(1) {
animation: rotate 3s infinite linear;
}
.item:nth-child(2) {
animation: rotate 3s infinite 1s linear;
}
.item:nth-child(3) {
animation: rotate 3s infinite 2s linear;
}
但是,在动画的前 2s,另外两个元素是不会动的,只有 2s 过后,整个动画才是我们想要的
此时,我们可以让第 2、3 个元素的延迟时间,改为负值,这样可以让动画延迟进行 -1s
、-2s
,也就是提前进行 1s
、2s
:
.item:nth-child(1) {
animation: rotate 3s infinite linear;
}
.item:nth-child(2) {
animation: rotate 3s infinite -1s linear;
}
.item:nth-child(3) {
animation: rotate 3s infinite -2s linear;
}
这样,每个元素都无需等待,直接就是运动状态中的,并且元素间隔位置是我们想要的结果
利用 animation-duration 和 animation-delay 构建随机效果,还有一个有意思的小技巧:同一个动画,我们利用一定范围内随机的 animation-duration
和一定范围内随机的 animation-delay
,可以有效的构建更为随机的动画效果,让动画更加的自然。
5、animation-timing-function 缓动函数
缓动函数在动画中非常重要,它定义了动画在每一动画周期中执行的节奏。缓动主要分为两类:
(1)cubic-bezier-timing-function 三次贝塞尔曲线缓动函数
首先先看看三次贝塞尔曲线缓动函数。在 CSS 中,支持一些缓动函数关键字。
/* Keyword values */
animation-timing-function: ease; // 动画以低速开始,然后加快,在结束前变慢
animation-timing-function: ease-in; // 动画以低速开始
animation-timing-function: ease-out; // 动画以低速结束
animation-timing-function: ease-in-out; // 动画以低速开始和结束
animation-timing-function: linear; // 匀速,动画从头到尾的速度是相同的
关于它们之间的效果对比
除了 CSS 支持的这 5 个关键字,我们还可以使用 cubic-bezier()
方法自定义三次贝塞尔曲线
animation-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
这里有个非常好用的网站 -- cubic-bezier (https://cubic-bezier.com/#.56,.19,.37,.74)用于创建和调试生成不同的贝塞尔曲线参数。
(2)step-timing-function 步骤缓动函数
接下来再讲讲步骤缓动函数。在 CSS 的 animation-timing-function
中,它有如下几种表现形态:
{
/* Keyword values */
animation-timing-function: step-start;
animation-timing-function: step-end;
/* Function values */
animation-timing-function: steps(6, start)
animation-timing-function: steps(4, end);
}
在 CSS 中,使用步骤缓动函数最多的,就是利用其来实现逐帧动画。假设我们有这样一张图
可以发现它其实是一个人物行进过程中的 6 种状态,或者可以为 6 帧,我们利用 animation-timing-function: steps(6)
可以将其用一个 CSS 动画串联起来,代码非常的简单:
<div class="box"></div>
.box {
width: 256px;
height: 256px;
background: url('https://github.com/iamalperen/playground/blob/main/SpriteSheetAnimation/sprite.png?raw=true');
animation: sprite .6s steps(6, end) infinite;
}
@keyframes sprite {
0% {
background-position: 0 0;
}
100% {
background-position: -1536px 0;
}
}
简单解释一下上述代码,首先要知道,刚好 256 x 6 = 1536
,所以上述图片其实可以刚好均分为 6 段:
(1)我们设定了一个大小都为 256px
的 div,给这个 div 赋予了一个 animation: sprite .6s steps(6) infinite
动画;
(2)其中 steps(6)
的意思就是将设定的 @keyframes 动画分为 6 次(6帧)执行,而整体的动画时间是 0.6s
,所以每一帧的停顿时长为 0.1s
;
(3)动画效果是由 background-position: 0 0
到 background-position: -1536px 0
,由于上述的 CSS 代码没有设置 background-repeat
,所以其实 background-position: 0 0
是等价于 background-position: -1536px 0
,就是图片在整个动画过程中推进了一轮,只不过每一帧停在了特点的地方,一共 6 帧;
将上述 1、2、3,3 个步骤画在图上简单示意:
从上图可知,其实在动画过程中,background-position
的取值其实只有 background-position: 0 0
,background-position: -256px 0
,background-position: -512px 0
依次类推一直到 background-position: -1536px 0
,由于背景的 repeat 的特性,其实刚好回到原点,由此又重新开始新一轮同样的动画。
所以,整个动画就会是这样,每一帧停留 0.1s 后切换到下一帧(注意这里是个无限循环动画),:
6、同个动画效果的补间动画和逐帧动画演绎对比
上述的三次贝塞尔曲线缓动和步骤缓动,其实就是对应的补间动画和逐帧动画。
对于同个动画而言,有的时候两种缓动都是适用的。我们在具体使用的时候需要具体分析选取。假设我们用 CSS 实现了这样一个图形:
现在想利用这个图形制作一个 Loading 效果,如果利用补间动画,也就是三次贝塞尔曲线缓动的话,让它旋转起来,得到的效果非常的一般:
.g-container{
animation: rotate 2s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
但是如果这里,我们将补间动画换成逐帧动画,因为有 20 个点,所以设置成 steps(20),再看看效果,会得到完全不一样的感觉:
.g-container{
animation: rotate 2s steps(20) infinite;
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
整个 loading 的圈圈看上去好像也在旋转,实际上只是 20 帧关键帧在切换,整体的效果感觉更适合 Loading 的效果。因此,两种动画效果都是很有必要掌握的,在实际使用的时候灵活尝试,选择更适合的。
7、animation-play-state
接下来,我们讲讲 animation-play-state
,顾名思义,它可以控制动画的状态:运行或者暂停。类似于视频播放器的开始和暂停。是 CSS 动画中有限的控制动画状态的手段之一。它的取值只有两个(默认为 running):
{
animation-play-state: paused | running;
}
使用起来也非常简单,看下面这个例子,我们在 hover 按钮的时候,实现动画的暂停:
<div class="btn stop">stop</div>
<div class="animation"></div>
.animation {
width: 100px;
height: 100px;
background: deeppink;
animation: move 2s linear infinite alternate;
}
@keyframes move {
100% {
transform: translate(100px, 0);
}
}
.stop:hover ~ .animation {
animation-play-state: paused;
}
animation-play-state 小技巧,默认暂停,点击运行
正常而言,按照正常思路使用 animation-play-state: paused
是非常简单的。但是,如果我们想创造一些有意思的 CSS 动画效果,不如反其道而行之。
我们都知道,正常情况下,动画应该是运行状态,那如果我们将一些动画的默认状态设置为暂停,只有当鼠标点击或者 hover 的时候,才设置其 animation-play-state: running
,这样就可以得到很多有趣的 CSS 效果。
8、animation-fill-mode 控制元素在各个阶段的状态
属性 animation-fill-mode
,很多人会误认为它只是用于控制元素在动画结束后是否复位。这个其实是不准确的,不全面的。看看它的取值:
{
// 默认值,当动画未执行时,动画将不会将任何样式应用于目标,而是使用赋予给该元素的CSS规则来显示该元素的状态
animation-fill-mode: none;
// 动画将在应用于目标时立即应用第一个关键帧中定义的值,并在 `animation-delay` 期间保留此值,
animation-fill-mode: backwards;
// 目标将保留由执行期间遇到的最后一个关键帧计算值。 最后一个关键帧取决于 `animation-direction` 和 `animation-iteration-count`
animation-fill-mode: forwards;
// 动画将遵循 `forwards` 和 `backwards` 的规则,从而在两个方向上扩展动画属性
animation-fill-mode: both;
}
none:一句话总结,元素在动画时间之外,样式只受到它的 CSS 规则限制,与 @keyframes 内的关键帧定义无关。
backwards:一句话总结,元素在动画开始之前(包含未触发动画阶段及 animation-delay
期间)的样式为动画运行时的第一帧,而动画结束后的样式则恢复为 CSS 规则设定的样式
forwards:一句话总结,元素在动画开始之前的样式为 CSS 规则设定的样式,而动画结束后的样式则表现为由执行期间遇到的最后一个关键帧计算值(也就是停在最后一帧)
both:一句话总结,综合了 animation-fill-mode: backwards
和 animation-fill-mode: forwards
的设定。动画开始前的样式为动画运行时的第一帧,动画结束后停在最后一帧
9、animation-iteration-count/animation-direction 动画循环次数和方向
animation-iteration-count
控制动画运行的次数,可以是数字或者 infinite
,注意,数字可以是小数
animation-direction
控制动画的方向,正向、反向、正向交替与反向交替
在上面讲述 animation-fill-mode
时,我使用了动画运行时的第一帧替代了@keyframes 中定义的第一帧这种说法,因为动画运行的第一帧和最后一帧的实际状态还会受到动画运行方向 animation-direction
和 animation-iteration-count
的影响。
在 CSS 动画中,由 animation-iteration-count
和 animation-direction
共同决定动画运行时的第一帧和最后一帧的状态。
10、动画的分治与复用
实现了一个 div 块下落动画,下落的同时产生透明度的变化
div {
animation: combine 2s;
}
@keyframes combine {
100% {
transform: translate(0, 150px);
opacity: 0;
}
}
//等价于
div {
animation: falldown 2s, fadeIn 2s;
}
@keyframes falldown {
100% {
transform: translate(0, 150px);
}
}
@keyframes fadeIn {
100% {
opacity: 0;
}
}
在 CSS 动画规则中,animation
是可以接收多个动画的,这样做的目的不仅仅只是为了复用,同时也是为了分治,我们对每一个属性层面的动画能够有着更为精确的控制。
11、keyframes 规则的设定:百分比与 from to 写法
12、动画状态的高优先级性
这也是很多人对 CSS 优先级的一个认知误区,在 CSS 中,优先级还需要考虑选择器的层叠(级联)顺序。只有在层叠顺序相等时,使用哪个值才取决于样式的优先级
学习文章:https://zhuanlan.zhihu.com/p/456713454