CSS 动画
引入
1.动画的原理
- 静止画面称作帧
- 将这些这帧以一定的速度进行播放,我们的视觉会产生残影形成动画效果。一般影视播放需要:1s/24帧,游戏需要1s/60帧。
2.浏览器的渲染过程
- 根据HTML创建HTML树(DOM)
- 根据CSS创建CSS树(CSSOM)
- 合并两棵树创建RENDER TRee(渲染树)
- LAYOUT 布局<文档流、盒模型、计算大小和位置以及文字的颜色>
- PAINT 绘制<把边框的颜色、文字颜色、以及阴影画出来>
- COMPOSE 合成根据层叠关系,进行展示画面
以下是三棵树

3. 如何更新样式
一般我们用JS更新样式
- div.remove() 对应下图的第一种方式,全走的方式,会触发当前消失,其他元素relayout。
- div.style.background='red' 改变背景颜色,直接跳过repaint+composite环节
- div.style.dispaly='none'
- div.classList.add('add')
不同的属性选择的渲染方式也不同,可以查看相关文档进行判断:点击查看更多
更新样式的三种方式

4.css动画优化方式
- JS优化: 使用repuestAnimationFrame代替setTimeout或者setlnterval
- css 优化: 使用will-change 或者translate
5.实现css 动画的属性
5.1 transform
transform属性允许你旋转,缩放,倾斜或平移给定元素。
- 位移 translate
- 缩放 scale
- 旋转 rotate
- 倾斜 skew
使用此属性的情况下,必须要配合 transition 过渡 行内元素(inline)不支持变形,需要先把它变成块元素(block)。
属性的演示 1.translate
<!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>
#demo {
width: 100px;
height: 200px;
border: 1px solid red;
margin: 50px;
}
#demo:hover {
transform: translateX(50px);
/* 向X轴移动50像素 */
transform: translateY(-50px);
/* 向Y轴移动-50像素 */
transform: translateZ(-200px);
/* 向Z轴移动-200像素 */
}
.wrapper {
perspective: 1000px;
/* 视觉大小为1000像素 */
/* perspective指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。 z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定 */
border: 1px solid black;
}
</style>
</head>
<body>
<div class="wrapper">
<div id="demo"></div>
</div>
</body>
</html>
2.scale 缩放
<!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>
#demo {
height: 300px;
width: 300px;
border: 1px solid palevioletred;
margin: 50px;
}
#demo:hover {
transform: scaleX(1.5);
/* X轴缩放1.5倍 */
transform: scaleY(0.5);
/* Y轴缩放0.5倍 */
/* transform: scale(1.5, 0.5); */
/* 另一种写法 */
}
.wrapper {
perspective: 1000px;
border: 5px solid blueviolet;
}
</style>
</head>
<body>
<div class="wrapper">
<div id="demo"></div>
</div>
</body>
</html>
3.rotate 旋转 一般用于360度旋转制作,loading。
<!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>
#demo {
height: 300px;
width: 300px;
border: 1px solid palevioletred;
margin: 150px;
}
#demo:hover {
transform: rotateX(45deg);
/* X轴旋转45度 */
transform: rotateY(90deg);
/* Y轴旋转90度 */
transform: rotateZ(30deg);
/* Z轴旋转30度 */
}
.wrapper {
perspective: 1000px;
border: 5px solid blueviolet;
}
</style>
</head>
<body>
<div class="wrapper">
<div id="demo"></div>
</div>
</body>
</html>




4.skew 倾斜
<!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>
#demo {
height: 300px;
width: 300px;
border: 1px solid palevioletred;
margin: 150px;
}
#demo:hover {
/* transform: skewX(45deg); */
/* X轴倾斜45度 */
transform: skewY(45deg);
/* Y轴倾斜90度 */
}
.wrapper {
perspective: 1000px;
border: 5px solid blueviolet;
}
</style>
</head>
<body>
<div class="wrapper">
<div id="demo"></div>
</div>
</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>
<style>
* {
box-sizing: border-box;
}
#heart {
display: inline-block;
margin: 100px;
position: relative;
transition: all 1s;
/* 过渡时间为1s */
}
#heart:hover {
transform: scale(1.2);
/* 缩放的比例1.2倍 */
}
#heart>.left {
background: red;
width: 50px;
height: 50px;
position: absolute;
transform: rotate(45deg) translateX(31px);
/* 旋转45度 X轴方向移动31像素 */
bottom: 50px;
left: -50px;
border-radius: 50% 0 0 50%;
/* 将正方形变成圆形 */
}
#heart>.right {
background: red;
width: 50px;
height: 50px;
border-radius: 50%;
position: absolute;
transform: rotate(45deg) translateY(31px);
bottom: 50px;
right: -50px;
border-radius: 50% 50% 0 0;
}
#heart>.bottom {
background: red;
width: 50px;
height: 50px;
transform: rotate(45deg);
}
</style>
</head>
<body>
<div id="heart">
<div class="left"></div>
<div class="right"></div>
<div class="bottom"></div>
</div>
</body>
</html>
5.2 transition
transition属性可以被指定为一个或多个 CSS 属性的过渡效果,多个属性之间用逗号进行分隔。 它的作用是补充中间帧。
5.2.1用法
- transition:属性名 时长 过渡的方式 延迟的时间 例如:
transition :left 200ms linear;
向左过渡 200ms时间
- 可以用逗号分隔两个不同属性
transition: left 200ms,top 200ms;
向左和向上做过渡动画 时间200ms
- all 可以代表所有属性
- 过渡的方式:linear ease ease-in 具体请查阅相关资料
注意:
不是所有的属性都可以过渡
- display:none 装换成 block 无法进行过渡
一般用visibility:hidden 转换成:visible
5.2.2 过渡必须有始有终
一般只有一次动画,或者是两次。
例如:hover 和非 hover状态的一个过渡 如果出现中间点怎么办呢?
解决的方式:
- 使用两次 transform 从a --- b 再从b --- c 用setTimeout 或者监听transitionend 事件的方式
#demo{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 50px;
transition: transform 1s linear;
}
#demo.b{
transform: translateX(200px);
}
#demo.c{
transform: translateX(200px) translateY(100px);
}
button.onclick = ()=>{
demo.classList.add('b')
setTimeout(()=>{
demo.classList.remove('b')
demo.classList.add('c')
},1000)
}
- 用animation 的方式 声明关键帧, 添加动画。
#demo{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 50px;
transition: transform 1s linear;
}
#demo.start{
animation: xxx 1.5s;
}
@keyframes xxx {
0% {
transform: none;
}
66.66%{
transform: translateX(200px);
}
100%{
transform: translateX(200px) translateY(100px);
}
}
button.onclick = ()=>{
demo.classList.add('start')
}
但是如果想得到动画停到最后一帧的情况呢? 在原有的基础上使用代码所示的方式即可实现。
#demo{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 50px;
}
#demo.start{
animation: xxx 1.5s forwards;
}
@keyframes xxx {
0% {
transform: none;
}
66.66%{
transform: translateX(200px);
}
100%{
transform: translateX(200px) translateY(100px);
}
}
6.animation的具体用法
animation:时长 过渡方式 延迟 次数 方向 填充模式 是否暂停 动画的名称
- 时长:1s or 1000ms
- 过渡方式: 与transition相似 有:linear等
- 次数:3或者2.4 或者infinite(无穷的)
- 方向:reverse alternate alternate-reverse(交替反向)
- 填充方式:none forwards backwards both
- 是否暂停:paused running
第二个红心
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>red heart</title>
<style>
* {
box-sizing: border-box;
}
#box {
display: inline-block;
margin: 100px;
position: relative;
/* background-color: red; */
/* border: 1px solid palegreen; */
animation: .3s heart infinite alternate-reverse;
}
#box:hover {
transform: scale(1.2);
}
#box>.left {
width: 100px;
height: 100px;
/* border: palegreen 1px solid; */
background: purple;
transform: rotate(45deg) translateX(62px);
/* 旋转45度,向X轴移动31像素 */
position: absolute;
bottom: 100px;
left: -100px;
border-radius: 50% 0 0 50%;
}
#box>.right {
width: 100px;
height: 100px;
/* border: palegreen 1px solid; */
background: purple;
transform: rotate(45deg) translateY(62px);
/* 旋转45度,向Y轴移动31像素 */
position: absolute;
bottom: 100px;
right: -100px;
border-radius: 50% 50% 0 0;
}
#box .bottom {
background: purple;
width: 100px;
height: 100px;
transform: rotate(45deg);
}
#name {
position: absolute;
/* top: 50px; */
right: 230px;
bottom: 60px;
color: royalblue;
}
#box1 {
display: inline-block;
margin: 100px;
position: relative;
/* background-color: red; */
/* border: 1px solid palegreen; */
/* transition: all 1s; */
animation: 1s heart infinite alternate-reverse;
}
@keyframes heart {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
}
}
/* #box1:hover {
transform: scale(1.2);
}
*/
#box1>.left1 {
width: 50px;
height: 50px;
/* border: palegreen 1px solid; */
background: red;
transform: rotate(45deg) translateX(31px);
/* 旋转45度,向X轴移动31像素 */
position: absolute;
bottom: 50px;
left: -50px;
border-radius: 50% 0 0 50%;
}
#box1>.right1 {
width: 50px;
height: 50px;
/* border: palegreen 1px solid; */
background: red;
transform: rotate(45deg) translateY(31px);
/* 旋转45度,向Y轴移动31像素 */
position: absolute;
bottom: 50px;
right: -50px;
border-radius: 50% 50% 0 0;
}
#box1 .bottom1 {
background: red;
width: 50px;
height: 50px;
transform: rotate(45deg);
}
#name1 {
position: absolute;
/* top: 50px; */
right: 230px;
bottom: 60px;
color: royalblue;
}
#box2 {
display: inline-block;
margin: 100px;
position: relative;
/* background-color: red; */
/* border: 1px solid palegreen; */
transition: all 1s;
}
#box2:hover {
transform: scale(1.2);
}
#box2>.left2 {
width: 50px;
height: 50px;
/* border: palegreen 1px solid; */
background: red;
transform: rotate(45deg) translateX(31px);
/* 旋转45度,向X轴移动31像素 */
position: absolute;
bottom: 50px;
left: -50px;
border-radius: 50% 0 0 50%;
}
#box2>.right2 {
width: 50px;
height: 50px;
/* border: palegreen 1px solid; */
background: red;
transform: rotate(45deg) translateY(31px);
/* 旋转45度,向Y轴移动31像素 */
position: absolute;
bottom: 50px;
right: -50px;
border-radius: 50% 50% 0 0;
}
#box2 .bottom2 {
background: red;
width: 50px;
height: 50px;
transform: rotate(45deg);
}
#box3 {
display: inline-block;
margin: 100px;
position: relative;
/* background-color: red; */
/* border: 1px solid palegreen; */
transition: all 1s;
}
#box3:hover {
transform: scale(1.2);
}
#box3>.left3 {
width: 50px;
height: 50px;
/* border: palegreen 1px solid; */
background: red;
transform: rotate(45deg) translateX(31px);
/* 旋转45度,向X轴移动31像素 */
position: absolute;
bottom: 50px;
left: -50px;
border-radius: 50% 0 0 50%;
}
#box3>.right3 {
width: 50px;
height: 50px;
/* border: palegreen 1px solid; */
background: red;
transform: rotate(45deg) translateY(31px);
/* 旋转45度,向Y轴移动31像素 */
position: absolute;
bottom: 50px;
right: -50px;
border-radius: 50% 50% 0 0;
}
#box3 .bottom3 {
background: red;
width: 50px;
height: 50px;
transform: rotate(45deg);
}
</style>
</head>
<body>
<div id="box">
<div class="left"></div>
<div class="right"></div>
<div class="bottom">
欧力给!
</div>
</div>
<!-- <span id="name">曹坤</span> -->
<div id="box1">
<div class="left1"></div>
<div class="right1"></div>
<div class="bottom1">
</div>
</div>
<!-- <span id="name1">曹坤</span> -->
<div id="box2">
<div class="left2"></div>
<div class="right2"></div>
<div class="bottom2">
</div>
</div>
</body>
</html>