唐抉的个人博客

CSS3动画详解

字数统计: 2.3k阅读时长: 9 min
2023/12/25

基本概念

css中有两种形式实现动画效果:过渡动画transition和自定义动画animation。其中,animation动画可以循环多次执行,而过渡动画transition只执行一遍。

transition

若通过用户的交互直接改变css样式,呈现的形式是立即转变。若希望这个变化是有过渡效果的,便需要使用到过渡动画transition。使用transition的例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<div>
<button @click="toggleVisibility">切换元素</button>
<transition name="fade">
<div v-if="isVisible" key="myElement" class="fade-element">
这是一个会淡入淡出的元素
</div>
</transition>
</div>
</template>

<script>
export default {
data() {
return {
isVisible: true,
};
},
methods: {
toggleVisibility() {
this.isVisible = !this.isVisible;
},
},
};
</script>

<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}

.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>

transition简写方式

1
transition: 使用过渡效果的属性名称  过渡时间 过渡方式

常见属性

transition-property:指定使用过渡效果的css属性

默认值为all,即所有能够被transition支持的属性都会有过渡效果。在实际使用时最好指定具体生效的属性,如只改变字体大小便设置为transition-property:font-size

目前transition不支持的过渡项有:z-indexdisplay

transition-duration:动画过渡时间

定义动画过渡时间,默认为0秒

transition-timing-function:动画过渡方式

定义动画的事件函数,控制动画速度,可以配置动画随时间变化的运动速率和轨迹。

可选值:

  • linear:动画的速度从头到尾都是相同的
  • ease(缓解):默认是动画从低速开始,然后加快,在结束前变慢
  • ease-in:动画以低速开始
  • ease-out:动画以低速结束
  • ease-in-out:动画以低速开始和结束
  • cubic-bezier(n,n,n,n):贝塞尔曲线(自定义数组),可到网站 cubic-bezier.com进行可视化配置

transition-delay: 动画延迟时间

设置动画延时时间,单位为秒。

若想要立即触发动画,只在恢复时延迟过渡,可以在动画触发时重新设置transition-delay:0s。这样动画一旦触发就会应用对应的样式表,动画执行完毕后延时0秒恢复原样式。

当同时使用多个动画时,可依次定义每个动画的延迟执行时间,依次来区分每一个动画。

多属性累加

需要对每个属性的过渡效果分别设置时,可以使用逗号,来分隔开。

1
2
3
4
transition-property: width, heitht, color ;
trnasition-duration: 1s, 1.5s, 2s ;
transition-timing-function: ease, linear, ease-in-out ;
transition-delay: 0s, 1s, 0s ;

以上代码也可以使用简写方式来分隔,如:

1
transition: width 1s ease ,heitht 1.5s linear 1s, color 2s ease-in-out ;

animation

自定义动画通过@keyframes来设置关键帧动画。可以对每一帧动画进行设置动画名称、时长、缓动函数、循环函数等信息。其语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@keyframes animationName {
0% {
/* 样式定义 */
width:50px;
height:50px;
}
50% {
/* 样式定义 */
width:100px;
height:100px;
}
100% {
/* 样式定义 */
width:50px;
height:50px;
}
}

/* 应用动画 */
.element {
animation: animationName 3s ease-in-out infinite;
}

其中,使用百分比来%指定变化时的状态,0%100%代表首尾帧,也可分别使用fromto来替代。

注意:若自定义动画没有自定义首尾帧,首尾帧将会应用元素原有的样式

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@keyframes animationName {
from {
/* 样式定义 */
width:50px;
height:50px;
}
50% {
/* 样式定义 */
width:100px;
height:100px;
}
to {
/* 样式定义 */
width:50px;
height:50px;
}
}

/* 将动画应用到元素上 */
.element {
animation: animationName 3s ease-in-out infinite;
}

animation简写方式

1
animation: 动画持续时间  延迟时间 执行关键帧名称 运动方式 循环次数 结束状态 动画执行顺序

最简方式:(其中执行时间和延迟时间顺序不可调整)

1
animation: 动画执行时间 执行关键帧名称

常见属性

animation-name:指定使用的 @keyframes 名称

若元素想要使用对应名称的动画,则需要配置animation-name。

animation-duration: 动画持续时间

定义动画持续时间,默认为0秒

animation-iteration-count: 动画循环次数

定义动画迭代次数/执行次数,默认为1次

animation-timing-function: 动画运动方式

定义动画的缓动函数,控制动画速度,可以配置动画随时间变化的运动速率和轨迹。

可选值:

  • linear:动画的速度从头到尾都是相同的
  • ease(缓解):默认是动画从低速开始,然后加快,在结束前变慢
  • ease-in:动画以低速开始
  • ease-out:动画以低速结束
  • ease-in-out:动画以低速开始和结束
  • cubic-bezier(n,n,n,n):贝塞尔曲线(自定义数组),可到网站 cubic-bezier.com进行可视化配置

animation-delay: 动画延迟时间

设置动画延时时间,单位为秒。

当同时使用多个动画时,可依次定义每个动画的延迟执行时间,依次来区分每一个动画。

animation-direction: 动画执行顺序(播放方向)

设置动画执行的方向。

可选值:

  • normal:默认值,动画按正常播放
  • reverse:动画反向播放
  • alternate(交替的):动画正反(正向->反向)交替执行
  • alternate-reverse:动画反正(反向->正向)交替执行
  • inherit:从父元素继承该属性

animation-fill-mode:动画结束状态

设置动画的填充模式

可选值:

  • none:默认值,动画在动画执行前后,不会应用任何样式到目标元素。
  • forwards:在动画结束后(由 animation-iteration-count 决定),目标元素将保持应用最后帧动画。
  • backwards:在动画结束后(由 animation-iteration-count 决定),目标元素将保持应用起始帧动画。

animation-play-state:动画执行状态

设置动画的执行状态

可选值:

  • running:允许
  • paused:暂停。动画将停止执行

多动画累加

若元素应用多个动画时,可以通过给animation属性分别不同值来分别控制各个动画的属性。各个值之间使用逗号,来分隔开。

1
2
3
4
5
animation-name: bgcolor, bodera, rotat;
animation-duration: 2s, 2s, 3s;
animation-iteration-count: 2, 2, 1;
animation-direction: reverse, normal, normal;
animation-fill-mode: forwards, forwards, forwards;

应用多个动画时,所有动画是并发执行的,因此计算动画结束事件只需要知道执行时间最长的动画即可,执行时间 x 单次执行时间=动画总时间。因此上述代码的最大时间=max(2x2,2x2,3x1=4s。

animation用法示例

播放时长为2秒的浮动动画的Vue代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
<div :class="{ 'custom-animation': isAnimating }"></div>
</template>

<script>
export default {
data() {
return {
isAnimating: true, // 根据需要设置是否启用动画
};
},
};
</script>

<style>
@keyframes customAnimation {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-30px);
}
}

.custom-animation {
width: 50px;
height: 50px;
background-color: green;
animation: customAnimation 2s ease-in-out infinite; /* 设置动画名称、时长、缓动函数和循环次数 */
}
</style>

常见错误及解决方案

@keyframes不能实现突变的状态变化

@keyframes是将样式从一个状态慢慢转变为另一个状态,因此不能实现突变的状态,例如:

1
2
3
4
5
6
7
div {
animation: appear 2s;
}
@keyframes appear {
from { display:none; }
to { display:block;}
}

上述代码中display:none;是将div不占空间地隐藏,而display:block;是显示div并占用空间。这里从display:none;display:block;的状态是突变的,因此@keyframes无法实现上述的状态变化

替代方法:

  • 占据空间的隐藏:使用visibility来代替display。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    div {
    animation: appear 2s;
    }
    @keyframes appear {
    from {
    opacity:1;
    visibility:visible;
    }
    to {
    opacity:0;
    visibility:hidden;
    }
    }

  • 不占据空间地隐藏:使用绝对定位+visibility组合,其中绝对定位使元素脱离文档流,搭配z-index层级关系来使他出现或消失。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    div {
    position:absolute;
    top:0;
    left:0;
    animation: appear 2s;
    }
    @keyframes appear {
    from {
    opacity:1;
    visibility:visible;
    z-index:10;
    }
    to {
    opacity:0;
    visibility:hidden;
    z-index:0;
    }
    }

  • 消失前占据空间但消失后不占空间:使用setTimeout和visibility组合。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <template>
    <div>
    <button @click="hideElement">隐藏元素</button>
    <div :class="{ 'fade-out': isVisible, 'hidden': !isVisible }">
    这是一个会消失的元素
    </div>
    </div>
    </template>

    <script>
    export default {
    data() {
    return {
    isVisible: true,
    };
    },
    methods: {
    hideElement() {
    this.isVisible = false;
    // 使用 setTimeout 设置一定的延迟,确保元素在消失前渲染一段时间
    setTimeout(() => {
    this.isVisible = true;
    }, 500); // 设置的时间可以根据需要调整
    },
    },
    };
    </script>

    <style>
    .fade-out {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.5s ease-in-out;
    }

    .hidden {
    visibility: hidden;
    opacity: 0;
    }
    </style>

@keyframes会增添/覆盖属性

以下为覆盖属性的例子:

1
2
3
4
5
6
7
8
9
10
11
12
/*
* div 在2s内下移200px
*/
div {
position:absolute;
top:0px;
animation: move 2s;
}
@keyframes move {
from { top:20px; }
to { top:200px;}
}

在例子里,div的初始状态是 top:0px;,在动画启动前,@keyframes先用top:20px;覆盖原属性,然后再开始播放动画

CATALOG
  1. 1. 基本概念
  2. 2. transition
    1. 2.1. transition简写方式
    2. 2.2. 常见属性
      1. 2.2.1. transition-property:指定使用过渡效果的css属性
      2. 2.2.2. transition-duration:动画过渡时间
      3. 2.2.3. transition-timing-function:动画过渡方式
      4. 2.2.4. transition-delay: 动画延迟时间
      5. 2.2.5. 多属性累加
  3. 3. animation
    1. 3.1. animation简写方式
    2. 3.2. 常见属性
      1. 3.2.1. animation-name:指定使用的 @keyframes 名称
      2. 3.2.2. animation-duration: 动画持续时间
      3. 3.2.3. animation-iteration-count: 动画循环次数
      4. 3.2.4. animation-timing-function: 动画运动方式
      5. 3.2.5. animation-delay: 动画延迟时间
      6. 3.2.6. animation-direction: 动画执行顺序(播放方向)
      7. 3.2.7. animation-fill-mode:动画结束状态
      8. 3.2.8. animation-play-state:动画执行状态
      9. 3.2.9. 多动画累加
    3. 3.3. animation用法示例
    4. 3.4. 常见错误及解决方案
      1. 3.4.1. @keyframes不能实现突变的状态变化
      2. 3.4.2. @keyframes会增添/覆盖属性