CSS动画

188 阅读6分钟

动画:

由许多静止的画面(帧),以一定的速度(如每秒30张)连续播放时,肉眼因视觉残象产生错觉,而误以为是活动的画面。

概念:

帧:每个静止的画面都叫帧。

将div从左往右移动

例:


HTML:
<body>
<div id="demo"></div>
</body>

CSS:
#demo{
  width:100px;
  height:100px;
  border:1px solid red;
  position: relative;
  left:0;
}

JS:
var n = 1
var id = setInterval(()=>{
  if(n <= 200){
  demo.style.left = n + 'px'
  n = n+1
  }else{
    console.log('1')
    clearInterval(id)
    }
},1000/60)

var id = ....

clearInterval(id)

做计时器,必须这样写,才能防止报错,必须给个id,然后clearInterval(id)

  • 原理: 每过一段时间【用setInterval(设置间隔) 做到】将div移动一小段距离,直到移动到目标地点。

在开发者工具界面的任何一个标签,按ESC出现一个rendering(┆选中即可),勾选paint flashing

渲染: 就是把某个区域重新画一下,绿色区域闪烁可以理解为擦掉重画。

  • 注意性能

绿色表示重新绘制(repaint),CSS渲染过程依次包含布局、绘制、合成。

其中布局和绘制有可能被省略。

前端高手不用left做动画,用transform(变形)

HTML:
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<div id="demo"></div>
</body>
</html>

CSS:
#demo{
  width: 100px;
  height: 100px;
  border:1px solid red;
  transition: all 1s linear;        
}
#demo.end{
  transform: translateX(200px);
}

JS:
setTimeout(()=>{
  demo.classList.add('end')
},5000)                    //5000是5秒的意思
  • 原理: transform:translateX(0 => 300px)

直接修改会被合成,需要等一会修改。

transtion过渡属性可以自动脑补中间帧。

  • 注意性能 并没有repaint(重新绘制),比改left性能好

浏览器渲染过程

步骤:

  1. 根据HTML构建HTML树(DOM)
  2. 根据CSS构建CSS树(CSSOM)
  3. 将两棵树合并成一颗渲染树(render tree)
  4. Layout布局(文档流、盒模型、机算大小和位置)
  5. Paint绘制(把边框颜色、文字颜色、阴影等画出来)
  6. Composite合成(根据层叠关系展示画面)

如何更新样式?

一般用JS来更新样式

比如 div.style.background = 'red'

比如 div.style.display = 'none'

比如 div.classList.add('red')

比如 div.remove() 直接删掉节点

三种不同的更新渲染方式

  1. JS/CSS > 样式 > 布局 > 绘制 > 合成

  2. JS/CSS > 样式 > 绘制 > 合成

  3. JS/CSS > 样式 > 合成

  • 第一种,全走 demo.remove( )会触发当前消失,其他元素 relayout (重新布局)

  • 第二种,跳过layout

改变背景颜色 ,直接repaint + composite

  • 第三种,跳过layout和paint 改变transform 只需composite 注意必须全屏看效果,在iframe里面看效果

查看每个属性触发什么流程,上 csstrigger.com

CSS动画优化

JS优化:

使用requstAnimationFrame代替,setTimeout或者setInterval。

CSS优化:

使用will-change或translate

transform全解

  • 四个常用功能
  1. 位移translate
  2. 缩放scale
  3. 旋转rotate
  4. 倾斜skew
  • 经验
  1. 一般都需要配合transition过渡
  2. inline元素不支持transform,需要很变成block

:hover定义:鼠标移动元素上时添加样式

transfor之translate

  • 常用写法

1. translateX(<length - percentage>)             //length: 长度
2. translateY(<length - percentage>)             //percentage: 百分数     


<length - percentage>表示可以跟一个长度 (比如20px) 或者 百分数(50%)

3. translate(<length - percentage> , <length - percentage>?)    //?表示可省略

例:

transform = translateX(50%) , 表示往右移动当前身位(宽度)的50%

transform = translateX(-50%) , 表示往左移动当前身位(宽度)的50%

transform = translateY(50%)则向下移动50% , -50%则向上

  1. transform = transformZ(<length>) 且要在父容器上加perspective 例:
HTML:
<div class = "wrapper">
<div id = "demo"></div>
</div>

CSS:
#demo: hover{
transform: translateZ(-200px);
}
.wrapper{
perspective: 1000px;
border: 1px solid red;
}

JSbin演示

5. translate3d(x,y,z)

  • 经验 1. 学会看懂MDN的语法示例

2. translate(-50% , -50%)可做绝对定位的居中

绝对定位居中,代码示例:

#demo{
width: 100px;
height: 100px;
border: 1px solid red;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50% , -50%);
}
.wrapper{
border: 1px solid red;
position: relative;
min-height: 500px;
}

transform之scale

常用写法:

ScaleX(<number>) X方向上(横向)缩放,大于1放大,小于1缩小,0消失

ScaleY(<number>) Y方向上(纵向)缩放,大于1放大,大于1缩小,0消失

Scale(<number>,<number>?) X、Y轴缩放同时进行

例:transform: scale(1.5);

经验:用得较少,因为容易出现模糊。

transform之rotate

常用写法:

rotate([<angle> | <zero>])        //默认不写Z  , angle: 角度  , |: 或  ,  zero: 零

例:transform: rotate(45deg); //角度的单位是deg , degree缩写

rotateZ([<angle> | <zero>])                //Z轴旋转
rotateX([<angle> | <zero>])                //X轴旋转
rotateY([<angle> | <zero>])                //Y轴旋转

transition: all 1s/0.5s/.5s;
transition(过渡;转变)不能放在:hover里,不然会丢失后半部分的动画

transition用于加动画效果,意思是1秒内完成动画,一般和transform联用

0.5s可以简写成.5s

rotate3d太复杂,用的时候再学

  • 经验: 一般用于360度旋转制作loading,用到时再看MDN

transform之skew

常用写法:

skewX([<angle> | <zero>]) 例:transform: skew(45deg); (deg角度单位)

skewY([<angle> | <zero>])

skew([<angle> | <zero>] , [<angle> | <zero>]?)

transform多重效果

组合使用

transform: scale(0.5) translate(-100% , -100%);
transform: none;                                   //取消所有
transform: scale(1.5) rotate(45deg);               //缩放后再旋转

可以自由组合,记得用空格隔开

border-radius: 50% 50% 50% 50%;

4个50%分别对应4个角,50%就是变圆,用来给边框border变圆

transition(过渡)

作用:补充中间帧

语法: transition:属性名 时长 过渡方式 延迟

例: transtion:left 200ms linear 300ms;

可以用逗号分隔两个不同的属性。

例:transition:left 200ms,top 400ms;

可以用all代表所有属性

例:transition: all 200ms;

过渡方式有:linear | ease | ease-in | ease-out | ease-inout | cubic-bezier | step-start | step-end | steps

具体含义要靠数学知识,不懂找MDN搜timing-function

  • 注意!

并不是所有属性都能过渡

display: block————none没法过渡

none————block也不行

让一个东西从看得见到看不见可以用opacity,但它有一个bug,就是消失以后还会占着一个原来的空间,因为知识控制透明度,位置还占着。需要在结束取消掉,一般不用。

一般改成visibility: visible————visibility: hidden;

但也会保留原来的位置空间

background颜色也可以过渡,比如,background: red——white

背景色过渡和visibility

过渡必须要有起始,一般只有一次动画,或者两次

比如,hover和非hover状态的过渡

如果除了起始,还有中间点,怎么办?

两种方法:

1. 使用两次transform

·a————transform—————·b

·b————transform—————·c

如何知道到了中间点呢?

用setTimeout或者监听transitionend事件

例:

HTML:
<div class="wrapper">
    <div id="demo"></div>
    <button id=button>开始</button>
</div>

CSS:
#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);        //translateX(200px)不加的话会偏移,忘了打一遍就会了
}
JS:
button.onclick=()=>{
demo.classList.add('b')
setTimeout(()=>{
demo.classList.remove('b')
demo.classList.add('c')
},1000)
}

2. 使用animation

  • 步骤:
  1. 声明关键帧
  2. 添加动画 例:
HTML:
<div class="wrapper">
    <div id="demo"></div>
    <button id=button>开始</button>
</div>

CSS:
#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);}
}
JS:
button.onclick =()=>{
demo.classList.add('start')
}

如何让动画停在最后一帧?

搜CSS animation stop at end

答案是加个forwards

在animation: xxx 1.5s forwards;

就停在最后一帧了

@keyframes完整语法

  1. 一种是from to

例如:

@keyframes slidein{
from{
transform:translateX(0%);
}
to{
transform:translateX(100%);
}
}
  1. 另一种是百分数
@keyframes xxx{
0%{..........;}
30%{.........;}
68%,72%{.........;}
100%{............;}
}

animation

animation: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充模式 | 是否暂停 | 动画名;

  1. 时长: 1s或1000ms

  2. 过渡方式:跟transition 取值一样,如 linear,ease

  3. 次数:3或者2.4,数字或小数都可以,再或者infinite(无限)

  4. 方向:reverse | alternate | alternate-reverse

  5. 填充模式:none | forwards | backwards | both

  6. 是否暂停:paused | running

以上所有属性都有对应的单独属性

暂停功能,代码示例:

<button id=xxx>暂停</button>
JS:xxx.onclick=()=>{
demo.style.animationPlayState='paused' | running(运行)
}

不懂去看MDN文档,然后实践敲一遍

跳动的红心之transform

animation之跳动红心