CSS帧动画
CSS帧动画
基础知识
通过定义一段动画中的关键点、关键状态来创建动画。@Keyframes
相比transition
对动画过程和细节有更强的控制。
过渡动画是两个状态间的变化,帧动画可以处理动画过程中不同时间的细节变化,
对过渡动画理解后再学习习帧动画会非常容易,也可以把帧动画理解为多个帧之间的过渡动画。
一句话,帧动画是CSS中的大杀器,你应该充分的了解并掌握它。
关键帧
使用@keyframes
规则配置动画中的各个帧
from 表示起始点
to表示终点
可以使用百分数如 20% 代表动画运行到20%处
基本使用
下面使用 @keyframes
定义了动画叫 radius
并配置了两个帧动作from/to
,然后在main:hover div
中使用animation-name
引用了动画并使用animation-duration
声明执行三秒。
注意:动画命名不要使用CSS关键字如
none
可以看到上面的动画是从30%
的圆角过渡到了50%
的圆角,但是整个动画的结束是瞬间结束,整个动画并不完美。
不要着急,下面会介绍各种方法让你的帧动画随心所欲。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 200px;
- width: 200px;
- display: flex;
- justify-content: center;
- align-items: center;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
-
- main:hover div{
- /* 一组帧的名字 */
- animation-name: radius;
- /* 动画时长 */
- animation-duration: 3s;
- }
-
- @keyframes radius{
- from{
- border-radius: 30%;
- }
- to{
- border-radius: 50%;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
时间点
帧动画需要定义在不同时间执行的动作,开始与结束可以使用 form/to
或 0%/100%
声明。
必须添加百分号,25%是正确写法
时间点没有顺序要求,即100%写在25%前也可以
未设置
0%
与100%
时将使用元素原始状态
你可以这么理解,目前所学的一组帧动画它的运行应该是这样的
初始状态 ---> 0% 或者 from ---> 100% 或者 to ---> 初始状态
所以现在看上面的动画,就知道为什么看起来比较生硬了。
物体移动
下面定义不同时间点来让物体元素移动一圈,下例中可以不设置from/to
系统将定义为元素初始状态。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: flex-start;
- align-items: flex-start;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
-
- main:hover div{
- /* 一组帧的名字 */
- animation-name: move;
- /* 动画时长 */
- animation-duration: 3s;
- }
-
- @keyframes move{
- /* 初始状态 ---> 帧 ---> 初始状态 */
- 25%{
- transform: translate(300px,0);
- }
- 50%{
- transform: translate(300px,300px);
- }
- 75%{
- transform: translate(0,300px);
- }
-
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
同时声明
时间点可以动画样式一样时可以一起声明,下面将25%/75%背景一起声明。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: flex-start;
- align-items: flex-start;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
-
- main:hover div{
- /* 一组帧的名字 */
- animation-name: move;
- /* 动画时长 */
- animation-duration: 3s;
- }
-
- @keyframes move{
- /* 初始状态 ---> 帧 ---> 初始状态 */
- 25%{
- transform: translate(300px,0);
- }
- 50%{
- transform: translate(300px,300px);
- }
- 75%{
- transform: translate(0,300px);
- }
-
- 25%,75%{
- background: #ff4757;
- }
-
- 50%,100%{
- background: #5352ed;
- }
-
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
使用动画
使用animation-name
规则可以在元素身上同时使用多个动画。
使用多个动画时用逗号分隔多个
动画有相同属性时,后面动画的属性优先使用
基本使用


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: flex-start;
- align-items: flex-start;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
-
- main:hover div{
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: move,radius;
- /* 动画时长 */
- animation-duration: 3s;
- }
-
- @keyframes move{
- /* 初始状态 ---> 帧 ---> 初始状态 */
- 25%{
- transform: translate(300px,0);
- }
- 50%{
- transform: translate(300px,300px);
- }
- 75%{
- transform: translate(0,300px);
- }
- /* 相同设置,前者不生效 */
-
- 25%,75%{
- background: #ff4757;
- }
-
- 50%,100%{
- background: #5352ed;
- }
-
- }
-
- @keyframes radius{
-
- 25%{
- border-radius: 50%;
- }
- 50%{
- border-radius: 30%;
- }
- 75%{
- border-radius: 50%;
- }
-
- /* 相同设置后者覆盖前者,所以移动时的颜色会变为下面两种 */
-
- 25%,75%{
- background: #ffa502;
- }
-
- 50%,100%{
- background: #2ed573;
- }
-
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
动画时间
使用 animation-duration
可以声明动画播放的时间,即把所有帧执行一遍所需要的时间。
可以使用m秒,ms毫秒时间单位
可为不同动画单独设置执行时间
如果动画数量大于时间数量,将重新从时间列表中计算 。 如一个动画有Move,Radius,Background 而时间是1s,2s,那么Move的时间是1s,Radius的时间是2s,Background的时间从头开始数,又是1s.
效果体验
如下图的过渡时间,圆角是六秒完成,背景色是四秒完成,移动是两秒完成,但是他们的开始时间都是一样的。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: center;
- align-items: flex-start;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
-
- main:hover div{
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: radius,background,move;
- /* 动画时长 圆角是六秒完成,背景色是四秒完成,移动是两秒完成,但是他们的开始时间都是一样的 */
- animation-duration: 6s,4s,2s;
- /* 将动画停留在最后一帧 */
- animation-fill-mode: forwards;
- }
-
- @keyframes radius{
- to{
- border-radius: 50%;
- }
- }
- @keyframes background{
- to{
- }
- }
- @keyframes move{
- to{
- transform: translate(0,150px);
- }
- }
-
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
动画属性
不是所有css属性都有过渡效果,查看支持动画的CSS属性 ,一般来讲有中间值的属性都可以设置动画如宽度、透明度等。
如何理解中间值?
比如,一个元素的宽度从100px变为200px,那么它们之间就有中间值。
而一个元素的边框样式从实心线变为虚心线,他们就没有中间值。
效果体验
看下面这张图,从实心线变为虚心线是瞬间变化,而背景颜色的改变却是跟着动画时间来进行渐变的。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: center;
- align-items: center;
- border: 1px solid #ddd;
- }
- div{
- height: 200px;
- width: 200px;
- background: #5352ed;
- /* 添加实心线 */
- border: 15px solid red;
- }
-
- main:hover div{
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: border-style,background;
- /* 动画时长 */
- animation-duration: 2s;
- /* 将动画停留在最后一帧 */
- animation-fill-mode: forwards;
-
- }
-
- @keyframes border-style{
- to{
- border:15px dotted red ;
- }
- }
- @keyframes background{
- to{
- }
- }
-
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
中间值
可以看下下面这个例子,左边的块from
与to
设置的尺寸单位没有中间值,所以是瞬间变大。
而右边块的from
与to
设置的尺寸单位是具有中间值的,所以是跟随动画时间进行渐变。


- <!DOCTYPE html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
-
- body {
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- main {
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- border: 1px solid #ddd;
- }
-
- main div:nth-child(1) {
-
- background: #5352ed;
- }
-
- main div:nth-child(2) {
-
- background: #ff4757;
- }
-
- main:hover div:nth-child(1) {
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: size-percentage;
- /* 动画时长 */
- animation-duration: 2s;
- /* 将动画停留在最后一帧 */
- animation-fill-mode: forwards;
-
- }
-
- main:hover div:nth-child(2) {
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: size-px;
- /* 动画时长 */
- animation-duration: 2s;
- /* 将动画停留在最后一帧 */
- animation-fill-mode: forwards;
-
- }
-
-
- @keyframes size-percentage {
-
- from {
- width: 200px;
- height: 200px;
- }
-
- /* px 与 % 之间没有中间值,所以是瞬间出现 */
-
- to {
- width: 50%;
- height: 50%;
- }
- }
-
- @keyframes size-px {
-
- from {
- width: 100px;
- height: 100px;
- }
-
- /* 有中间值,跟随动画时间进行渐变 */
-
- to {
- width: 200px;
- height: 200px;
- }
- }
- </style>
- </head>
-
- <body>
- <main>
- <div></div>
- <div></div>
- </main>
- </body>
-
- </html>
代码示例
重复动画
使用animation-iteration-count
规则设置动画重复执行次数,可以给一个数字。当设置值为 infinite
表示无限循环执行。
可同时设置元素的多个动画重复,使用逗号分隔
如果动画数量大于重复数量定义,后面的动画将重新计算重复
效果体验
如下面这个案例,移动的次数是一次,而变化圆角是无限次。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: flex-start;
- align-items: flex-start;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
-
- main:hover div{
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: move,radius;
- /* 动画时长 */
- animation-duration: 3s;
- /* 代表移动只走一遍,随后就不断的圆角变化,进入死循环 */
- animation-iteration-count: 1,infinite;
- }
-
- @keyframes move{
- /* 初始状态 ---> 帧 ---> 初始状态 */
- 25%{
- transform: translate(300px,0);
- }
- 50%{
- transform: translate(300px,300px);
- }
- 75%{
- transform: translate(0,300px);
- }
- /* 相同设置,前者不生效 */
-
- 25%,75%{
- background: #ff4757;
- }
-
- 50%,100%{
- background: #5352ed;
- }
-
- }
-
- @keyframes radius{
-
- 25%{
- border-radius: 50%;
- }
- 50%{
- border-radius: 30%;
- }
- 75%{
- border-radius: 50%;
- }
-
- /* 相同设置后者覆盖前者,所以移动时的颜色会变为下面两种 */
-
- 25%,75%{
- background: #ffa502;
- }
-
- 50%,100%{
- background: #2ed573;
- }
-
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
心动感觉
使用循环动画绘制心动效果。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css">
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: center;
- align-items: center;
- border: 1px solid #ddd;
- }
- main i.iconfont{
- font-size: 100px;
- color: red;
- }
- main:hover i{
- /* 添加一组帧动画 */
- animation-name: xin;
- /* 时间 */
- animation-duration: .5s;
- /* 循环次数 死循环 */
- animation-iteration-count: infinite;
- }
- @keyframes xin {
- to{
- opacity: .5;
- font-size: 120px;
- }
- 20%{
- opacity: .6;
- font-size: 130px;
- }
- 40%{
- opacity: .7;
- font-size: 140px;
- }
- 60%{
- opacity: .8;
- font-size: 150px;
- }
- 80%{
- opacity: .9;
- font-size: 160px;
- }
- to{
- opacity: 1;
- font-size: 140px;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <i class="iconfont icon-xin"></i>
- </main>
- </body>
- </html>
代码示例
动画方向
使用 animation-direction
控制动画运行的方向。
选项 | 说明 |
---|---|
normal | 从0%到100%运行动画 |
reverse | 从100%到0%运行动画 |
alternate | 先从0%到100%,然后从100%到0% |
alternate-reverse | 先从100%到0%,然后从0%到100% |
效果对比


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css">
- <style>
- * {
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body {
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main {
- height: 400px;
- width: 800px;
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- border: 1px solid #ddd;
- }
- main i.iconfont {
- font-size: 100px;
- color: red;
- position: relative;
- }
- main:hover i {
- /* 添加一组帧动画 */
- animation-name: xin;
- /* 时间 */
- animation-duration: .5s;
- /* 循环次数 死循环 */
- animation-iteration-count: infinite;
- }
- main i:nth-child(1):after {
- content: "normal";
- font-size: 15px;
- color: white;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- }
- main i:nth-child(2):after {
- content: "normal-reverse";
- font-size: 15px;
- color: white;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- }
- main i:nth-child(3):after {
- content: "alternate";
- font-size: 15px;
- color: white;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- }
- main i:nth-child(4):after {
- content: "alternate-reverse";
- font-size: 15px;
- color: white;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- }
- main:hover i:nth-child(1) {
- /* 0-100 */
- animation-direction: normal;
- }
- main:hover i:nth-child(2) {
- /* 100-0 */
- animation-direction: reverse;
- }
- main:hover i:nth-child(3) {
- /* 0-100 100-0 */
- animation-direction: alternate;
- }
- main:hover i:nth-child(4) {
- /* 100-0 0-100 */
- animation-direction: alternate-reverse;
- }
- @keyframes xin {
- to {
- opacity: .5;
- font-size: 120px;
- }
- 20% {
- opacity: .6;
- font-size: 130px;
- }
- 40% {
- opacity: .7;
- font-size: 140px;
- }
- 60% {
- opacity: .8;
- font-size: 150px;
- }
- 80% {
- opacity: .9;
- font-size: 160px;
- }
- to {
- opacity: 1;
- font-size: 140px;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <i class="iconfont icon-xin"></i>
- <i class="iconfont icon-xin"></i>
- <i class="iconfont icon-xin"></i>
- <i class="iconfont icon-xin"></i>
- </main>
- </body>
- </html>
代码示例
弹跳球
alternate-reverse
是100-0 0-100,因此非常适合用来做弹跳球。
我们先把球和阴影都定义在下方,然后使用alternate-reverse
将球转移到上方即可。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css">
- <style>
- * {
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body {
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main {
- height: 400px;
- width: 400px;
- display: flex;
- flex-flow: column;
- justify-content: flex-end;
- align-items: center;
- border: 1px solid #ddd;
- }
- main div {
- height: 100px;
- width: 100px;
- background: linear-gradient(45deg, #7bed9f, #2ed573, #1e90ff, #3742fa);
- border-radius: 50%;
- }
- main section {
- width: 140px;
- height: 20px;
- background: #2f3542;
- border-radius: 75%;
- /* 高斯模糊 */
- filter: blur(3px);
- }
- main:hover div {
- /* 添加一组帧动画 */
- animation-name: beat;
- /* 动画时间 */
- animation-duration: 1s;
- /* 运动方式 100-0 0-100 */
- animation-direction: alternate-reverse;
- /* 死循环 */
- animation-iteration-count: infinite;
- }
- main:hover section {
- /* 添加一组帧动画 */
- animation-name: size;
- /* 动画时间 */
- animation-duration: 1s;
- /* 运动方式 100-0 0-100 */
- animation-direction: alternate-reverse;
- /* 死循环 */
- animation-iteration-count: infinite;
- }
- @keyframes beat {
- from{
- background: linear-gradient(90deg, #7bed9f, #2ed573, #1e90ff, #3742fa);
- width: 140px;
- }
- to {
- transform: translateY(-280px);
- }
- }
- @keyframes size{
- to{
- width: 70px;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- <section></section>
- </main>
- </body>
- </html>
代码示例
延迟动画
使用 animation-delay
规则定义动画等待多长时间后执行。
我们可以为多个动画指定不同的延迟时间,与动画时间的使用规则相同。
效果体验
延迟动画 圆角3s后执行,背景色2s后执行,移动1s后执行


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: center;
- align-items: flex-start;
- border: 1px solid #ddd;
- }
- div{
- height: 100px;
- width: 100px;
- background: #5352ed;
- }
- main:hover div{
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: radius,background,move;
- /* 动画时长 */
- animation-duration: 2s;
- /* 延迟动画 圆角3s后执行,背景色2s后执行,移动1s后执行*/
- animation-delay:3s,2s,1s;
- /* 将动画停留在最后一帧 */
- animation-fill-mode: forwards;
- }
- @keyframes radius{
- to{
- border-radius: 50%;
- }
- }
- @keyframes background{
- to{
- background-color: #ffa502;
- }
- }
- @keyframes move{
- to{
- transform: translate(0,150px);
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- </main>
- </body>
- </html>
代码示例
动画速率
系统属性
使用animation-timing-function
来控制动画速率
值 | 描述 |
---|---|
linear | 规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。 |
ease | 开始慢,然后快,慢下来,结束时非常慢(cubic-bezier(0.25,0.1,0.25,1))默认值。 |
ease-in | 开始慢,结束快(等于 cubic-bezier(0.42,0,1,1)) |
ease-out | 开始快,结束慢(等于 cubic-bezier(0,0,0.58,1)) |
ease-in-out | 中间快,两边慢(等于 cubic-bezier(0.42,0,0.58,1)) |
cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中定义自己的值 |
可以在帧中单独定义,将影响当前帧的速率
贝塞尔曲线
其实不管是linear
或者是ease
都是由贝塞尔曲线来完成的。
我们需要设置四个值 cubic-bezier(<x1>, <y1>, <x2>, <y2>)
来控制曲线速度,可在 https://cubic-bezier.com 网站在线体验效果。
效果体验


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: space-evenly;
- align-items: flex-end;
- border: 1px solid #ddd;
- }
- div{
- padding: 10px;
- height: 100%;
- width: 25%;
- text-align: center;
- background: #ff4757 content-box;
- color: white;
- }
- main:hover div{
- /* 一组帧的名字 可以使用多组帧*/
- animation-name: move;
- /* 动画时长 */
- animation-duration: 3s;
- /* 重复动画 死循环 */
- animation-iteration-count: infinite;
- }
- main:hover div:nth-child(1){
- animation-timing-function: linear;
- }
- main:hover div:nth-child(2){
- animation-timing-function: ease;
- }
- main:hover div:nth-child(3){
- animation-timing-function: ease-in;
- }
- main:hover div:nth-child(4){
- animation-timing-function: ease-out;
- }
- main:hover div:nth-child(5){
- animation-timing-function: ease-in-out;
- }
- @keyframes move{
- to{
- height: 0;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div>linear</div>
- <div>ease</div>
- <div>ease-in</div>
- <div>ease-out</div>
- <div>ease-in-out</div>
- </main>
- </body>
- </html>
代码示例
弹跳球
ease-out
是开始快,结束慢,而ease-in
是结束快,开始慢。因此这两个组合做弹跳小球刚好。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css">
- <style>
- * {
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body {
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main {
- height: 400px;
- width: 400px;
- display: flex;
- flex-flow: column;
- justify-content: space-between;
- align-items: center;
- border: 1px solid #ddd;
- }
- main div {
- height: 100px;
- width: 100px;
- background: linear-gradient(45deg, #eccc68, #ffa502, #ff6b81, #ff4757);
- border-radius: 50%;
- }
- main section {
- width: 70px;
- height: 20px;
- background: #2f3542;
- border-radius: 75%;
- /* 高斯模糊 */
- filter: blur(3px);
- }
- main:hover div {
- /* 添加一组帧动画 */
- animation-name: beat;
- /* 动画时间 */
- animation-duration: 3s;
- /* 死循环 */
- animation-iteration-count: infinite;
- }
- main:hover section {
- /* 添加一组帧动画 */
- animation-name: size;
- /* 动画时间 */
- animation-duration: 3s;
- /* 死循环 */
- animation-iteration-count: infinite;
- }
- @keyframes beat {
- 0% {
- background: linear-gradient(60deg, #eccc68, #ffa502, #ff6b81, #ff4757);
- transform: translateY(0px);
- animation-timing-function: ease-in;
- width: 100px;
- }
- 30% {
- background: linear-gradient(120deg, #eccc68, #ffa502, #ff6b81, #ff4757);
- transform: translateY(50px);
- animation-timing-function: ease-in;
- width: 100px;
- }
- 60% {
- background: linear-gradient(240deg, #eccc68, #ffa502, #ff6b81, #ff4757);
- transform: translateY(100px);
- animation-timing-function: ease-in;
- width: 100px;
- }
- 80% {
- background: linear-gradient(300deg, #eccc68, #ffa502, #ff6b81, #ff4757);
- transform: translateY(150px);
- animation-timing-function: ease-in;
- width: 100px;
- }
- 95% {
- background: linear-gradient(340deg, #eccc68, #ffa502, #ff6b81, #ff4757);
- transform: translateY(200px);
- animation-timing-function: ease-in;
- width: 100px;
- }
- 15%,
- 45%,
- 70%,
- 85%,
- 100% {
- width: 140px;
- transform: translateY(280px);
- animation-timing-function: ease-out;
- }
- }
- @keyframes size {
- 0% {
- width: 80px;
- }
- 30% {
- width: 85px;
- }
- 60% {
- width: 95px;
- }
- 80% {
- width: 110px;
- }
- 95% {
- width: 120px;
- }
- 15%,
- 45%,
- 70%,
- 85%,
- 100% {
- width: 140px;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- <section></section>
- </main>
- </body>
- </html>
代码示例
按钮提交
这个需要用到盒子阴影,一个元素可以有多个阴影。
盒子阴影的设置规则如下:
水平偏移度/垂直偏移度/模糊度/颜色
对于颜色而言可以使用currentColor
来获取当前盒子的color
属性。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css">
- <style>
- * {
- margin: 0;
- padding: 0;
- list-style: none;
- box-sizing: border-box;
- }
- body {
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main {
- height: 400px;
- width: 400px;
- display: flex;
- justify-content: center;
- align-items: center;
- border: 1px solid #ddd;
- }
- main button {
- height: 40px;
- width: 100px;
- background-color: #747d8c;
- color: white;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main button::after {
- content: '';
- display: inline-block;
- height: 3px;
- width: 3px;
- margin-left: 5px;
- }
- /* Js中可换成点击事件 */
- button:hover::after {
- /* 添加一组帧动画 */
- animation-name: point;
- /* 动画时间 */
- animation-duration: 2s;
- /* 死循环 */
- animation-iteration-count: infinite;
- /* 动画速率 */
- animation-timing-function: linear;
- }
- @keyframes point {
- 60%{
- box-shadow: none;
- }
- 30% {
- box-shadow: 3px 0 currentColor;
- }
- 60% {
- box-shadow: 3px 0 currentColor, 9px 0 currentColor;
- }
- to {
- box-shadow: 3px 0 currentColor, 9px 0 currentColor, 15px 0 currentColor;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <button>提交</button>
- </main>
- </body>
- </html>
代码示例
步进速度
过渡使用阶梯化呈现,有点像现实生活中的机械舞,下面是把过渡分3步完成。
选项 | 说明 |
---|---|
steps(n,start) | 设置n个时间点,第一时间点变化状态 |
steps(n,end) | 设置n个时间点,第一时间点初始状态 |
step-start | 等于steps(1,start),可以理解为从下一步开始 |
step-end | 等于steps(1,end),可以理解为从当前步开始 |
start
总是先走,end
总是后走。


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- *{
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body{
- height: 100vh;
- width: 100vw;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main{
- height: 400px;
- width: 800px;
- display: flex;
- border:1px solid #ddd;
- position: relative;
- }
- main div{
- width: 200px;
- height: 100%;
- border: 1px solid #ddd;
- }
- main::after{
- content: "START";
- height: 30%;
- width: 25%;
- background: #ff4757;
- color: #fff;
- font-size: 2em;
- position: absolute;
- top: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main::before{
- content: "END";
- height: 30%;
- width: 25%;
- background: #70a1ff;
- color: #fff;
- font-size: 2em;
- position: absolute;
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- main:hover::after{
- /* 添加一组动画帧 */
- animation-name: move;
- /* 步进动画,3步 */
- animation-timing-function: steps(3,start);
- /* 动画时长2s */
- animation-duration: 2s;
- }
- main:hover::before{
- /* 添加一组动画帧 */
- animation-name: move;
- /* 步进动画,3步 */
- animation-timing-function: steps(3,end);
- /* 动画时长2s */
- animation-duration: 2s;
- }
- @keyframes move{
- to{
- transform: translateX(600px);
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- </main>
- </body>
- </html>
代码示例
播放状态
使用 animation-play-state
可以控制动画的暂停与运行。
选项 | 说明 |
---|---|
paused | 鼠标放上时暂停 |
running | 鼠标放上时运行 |
轮播图


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- * {
- padding: 0;
- margin: 0;
- }
- body {
- width: 100vw;
- height: 100vh;
- display: flex;
- justify-content: center;
- align-items: center;
- background: #2c3e50;
- }
- main {
- width: 400px;
- border: solid 5px #ddd;
- border-width: 5px 0 5px 0;
- overflow: hidden;
- position: relative;
- }
- main:hover section {
- animation-play-state: paused;
- }
- main:hover ul::before {
- animation-play-state: paused;
- }
- section {
- width: 1600px;
- height: 200px;
- display: flex;
- flex-direction: row;
- animation-name: slide;
- animation-duration: 4s;
- animation-iteration-count: infinite;
- animation-timing-function: steps(4, end);
- }
- section div {
- width: 400px;
- height: 200px;
- overflow: hidden;
- }
- section div img {
- width: 100%;
- }
- ul {
- width: 200px;
- position: absolute;
- list-style: none;
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 3;
- bottom: 20px;
- left: 50%;
- transform: translateX(-50%);
- }
- ul li {
- font-size: 2em;
- font-weight: bold;
- color: white;
- width: 50px;
- height: 50px;
- border-radius: 50%;
- border: solid 3px transparent;
- box-sizing: border-box;
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 2;
- background: rgba(0, 0, 0, .3);
- box-shadow: 0 0 3px rgba(0, 0, 0, 1);
- }
- ul::before {
- content: '';
- width: 50px;
- height: 50px;
- border-radius: 50%;
- position: absolute;
- background: #e74c3c;
- left: 0;
- animation-name: num;
- animation-duration: 4s;
- animation-iteration-count: infinite;
- animation-timing-function: steps(4, end);
- z-index: 1;
- }
- @keyframes slide {
- from {
- transform: translateX(0px);
- }
- to {
- transform: translateX(-100%);
- }
- }
- @keyframes num {
- 100% {
- transform: translateX(200px);
- }
- }
- </style>
- </head>
- <body>
- <main>
- <section>
- <div>
- <img src="1.jpg" alt="">
- </div>
- <div>
- <img src="2.jpg" alt="">
- </div>
- <div>
- <img src="3.jpg" alt="">
- </div>
- <div>
- <img src="4.jpg" alt="">
- </div>
- </section>
- <ul>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- </ul>
- </main>
- </body>
- </html>
代码示例
填充模式
animation-fill-mode
用于定义动画播放结束后的处理模式,是回到原来状态还是停止在动画结束状态。
选项 | 说明 |
---|---|
none | 需要等延迟结束,起始帧属性才应用 |
backwards | 动画效果在起始帧,不等延迟结束 |
forwards | 结束后停留动画的最后一帧 |
both | 包含backwards与forwards规则,即动画效果在起始帧,不等延迟结束,并且在结束后停止在最后一帧 |
效果对比


- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: content-box;
- }
- body{
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- width: 100vw;
- }
- main{
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- height: 200px;
- width: 800px;
- border: 1px solid #ddd;
- }
- div{
- height: 80px;
- width: 200px;
- background: #000 content-box;
- padding: 10px;
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- color: #fff;
- position: relative;
- }
- main:hover div{
- /* 添加一组帧动画 */
- animation-name: background;
- /* 运行时间 */
- animation-duration: 3s;
- /* 延迟时间 */
- animation-delay: 2s;
- }
- main div:nth-child(1)::before{
- content: "等待延迟 不停留最后一帧";
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- color: red;
- font-weight: bolder;
- position: absolute;
- top: -20px;
- }
- main div:nth-child(2)::before{
- content: "不等待延迟 不停留最后一帧 ";
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- color: red;
- font-weight: bolder;
- position: absolute;
- top: -20px;
- }
- main div:nth-child(3)::before{
- content: "等待延迟 停留最后一帧 ";
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- color: red;
- font-weight: bolder;
- position: absolute;
- top: -20px;
- }
- main div:nth-child(4)::before{
- content: "不等待延迟 停留最后一帧 ";
- display: flex;
- justify-content: space-evenly;
- align-items: center;
- color: red;
- font-weight: bolder;
- position: absolute;
- top: -20px;
- }
- main:hover div:nth-child(1){
- animation-fill-mode: none;
- }
- main:hover div:nth-child(2){
- animation-fill-mode: backwards;
- }
- main:hover div:nth-child(3){
- animation-fill-mode: forwards;
- }
- main:hover div:nth-child(4){
- animation-fill-mode: both;
- }
- @keyframes background{
- from{
- background-color: #ff6348;
- }
- 30%{
- background-color: #ffa502;
- }
- 60%{
- background-color: #eccc68;
- }
- to{
- background-color: #2ed573;
- }
- }
- </style>
- </head>
- <body>
- <main>
- <div>none</div>
- <div>backwards</div>
- <div>forwards</div>
- <div>both</div>
- </main>
- </body>
- </html>
代码示例
简写模式
和CSS中的其他属性一样,可以使用animation
组合定义帧动画。animation 属性是一个简写属性,用于设置六个动画属性:
animation-name 帧动画名字
animation-duration 帧动画运行时间
animation-timing-function 帧动画速率
animation-delay 帧动画播放状态(暂停/运行)
animation-iteration-count 帧动画循环次数
animation-direction 延迟时间
必须存在 animation-duration
属性,否则过渡时间为0没有动画效果。
CSS帧动画的更多相关文章
- 使用javascript和css模拟帧动画的几种方法浅析
我们平时在开发前端页面的时候,经常会播放一段帧序列.这段帧序列就像gif图片那样,反复循环播放.那大家可能会说,直接用gif图片就好了,干嘛还去模拟呢?那是因为要做得更加灵活,我们要做到以下几点: 1 ...
- CSS技巧:逐帧动画抖动解决方案
笔者所在的前端团队主要从事移动端的H5页面开发,而团队使用的适配方案是: viewport units + rem.具体可以参见凹凸实验室的文章 – 利用视口单位实现适配布局 . 笔者目前(2017. ...
- CSS动画-step()帧动画
Twitter使用了一种新的动画形式,使用一系列的图片来创建帧动画. 下面是一个❤动画,鼠标移动到上面开始绽放. .heart { width: 100px; height: 100px; backg ...
- 深入理解CSS3 Animation 帧动画
CSS3我在5年之前就有用了,包括公司项目都一直在很前沿的技术. 最近在写慕课网的七夕主题,用了大量的CSS3动画,但是真的沉淀下来仔细的去深入CSS3动画的各个属性发现还是很深的,这里就写下关于帧动 ...
- 3d图片切换(css3帧动画)
效果带抖动翻转隐藏,使用帧动画 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...
- css3 实现逐帧动画
css3 实现逐帧动画 实现逐帧动画需要使用到的是Animation动画,该CSS3的Animation有八个属性:分别是如下:1: animation-name2: animation-durati ...
- 深入理解CSS3 Animation 帧动画 ( steps )
作者:Aaron的博客 网址:http://www.cnblogs.com/aaronjs/p/4642015.html --------------------------------------- ...
- 利用css3-animation来制作逐帧动画
前言 趁着还没有元旦之前先码一篇文章,不然到时候估计又被各种虐了,所以趁现在还有力气先来一篇.今天来聊聊css3中的动画属性animation,对这个属性懵懂是在很早的时候有前辈用这个 animati ...
- 深入理解CSS3 Animation 帧动画(转)
CSS3我在5年之前就有用了,包括公司项目都一直在很前沿的技术. 最近在写慕课网的七夕主题,用了大量的CSS3动画,但是真的沉淀下来仔细的去深入CSS3动画的各个属性发现还是很深的,这里就写下关于帧动 ...
随机推荐
- LQR要点
新的“A”变成着了这样:Ac = A - KB 基于对象:状态空间形式的系统 能量函数J:也称之为目标函数 Q:半正定矩阵,对角阵(允许对角元素出现0) R:正定矩阵,QR其实就是权重 下面这段话可能 ...
- caffe的python接口学习(5)生成deploy文件
如果要把训练好的模型拿来测试新的图片,那必须得要一个deploy.prototxt文件,这个文件实际上和test.prototxt文件差不多,只是头尾不相同而也.deploy文件没有第一层数据输入层, ...
- Java使用IO流读取TXT文件
通过BufferedReader读取TXT文件window系统默认的编码是GBK,而IDE的编码多数为UTF-8,如果没有规定new InputStreamReader(new FileInputSt ...
- Nginx使用upstream实现负载均衡
如果Nginx没有仅仅只能代理一台服务器的话,那它也不可能像今天这么火,Nginx可以配置代理多台服务器,当一台服务器宕机之后,仍能保持系统可用.具体配置过程如下: 1. 在http节点下,添加ups ...
- 在Ubuntu 16.04上编译OpenJDK8的源代码
本文将详细介绍在Ubuntu16.04上对OpenJDK8进行编译. 1.准备编译环境 使用的操作系统为Ubuntu16.04,如果读者没有安装Ubuntu,可以在Windows上使用虚拟机的方式进行 ...
- Tornado之异步非阻塞
同步模式:同步模式下,只有处理完前一个任务下一个才会执行 class MainHandler(tornado.web.RequestHandler): def get(self): time.slee ...
- Spring Boot -- 启动流程分析之ApplicationContext 中
上一节我们已经分析到AbsractApplicationContext类refresh方法中的postProcessBeanFactory方法,在分析registerBeanPostProcessor ...
- 相邻元素之间的margin合并问题
任何元素都可以设置border 设置宽高可能无效 行内元素设置padding,margin上下是无效的,左右是有效的 外边距合并:指的是,当两个垂直外边距相遇时,它们将形成一个外边距. 合并后的外边距 ...
- sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
1.首先,问题出现的点是在泛型 我出现问题的原因是,和泛型有关系,要调整泛型 2.我把问题出现的过程描述一哈子 1.基础类 @tk.mybatis.mapper.annotation.Register ...
- Pop!_OS安装与配置(三):系统美化
Pop!_OS系统美化 首先上效果图,美化完是这样的: 那么接下来就一步步进行美化吧 主要参考:Ubuntu 18.04 美化配置--leo.rd 1.安装tweak sudo apt install ...