CSS动画

172 阅读4分钟

一个简单的例子

将div从左往右移动

js.jirengu.com/bagow/1/edi…

原理

  • 没过一段时间(用setInterval做到)
  • 将div移动一小段距离
  • 直到移动到目标地点

注意性能

  • 红色格子一直在重新绘制(repaint)

同样的效果用transform

js.jirengu.com/lojiz/1/edi…

原理

  • transform: translateX(0 => 300px);
  • transition过渡属性可以自动脑补中间帧

注意性能

  • 只在开始和最后repaint
  • 比改left性能好

浏览器渲染原理

浏览器渲染过程

步骤

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

三棵树

316753b3dcd248782dd1f06b0b3098b.png

如何更新样式

一般我们用JS来更新样式

  • 比如 div.style.background = 'red'
  • 比如 div.style.display = 'none'
  • 比如 div.classList.add('red') /直接更新类更好一点/
  • 比如 div.remove() 直接删掉节点

三种不同渲染(更新)方式

94b243dd8e894fb720bcb431cef0e95.png

每个属性都触发什么流程:csstriggers.com/

CSS动画优化

  • Google写的文章
  • JS优化
    • 使用requsetAnimationFrame代替setTimeout或setInterval
  • CSS优化
    • 使用will-change或translate

transform介绍

四个常用功能

  • 位移 translate
  • 缩放 scale
  • 旋转 rotate
  • 倾斜 skew

经验

  • 一般都需要配合transition过度
  • inline元素不支持transform,需要先变成block

transform之translate

常用写法

  • translateX( < length-percentage > )/ * 值/百分数 * /
  • translateY( < length-percentage > )
  • translate( < length-percentage > ,< length-percentage > )
  • translateZ( < length > )
  • translate3d(x,y,z)
  <div class="wrapper">
    <div id="demo"></div>
  </div>
#demo{
  width: 100px;
  height: 200px;
  border: 1px solid red;
  margin: 50px;
}
#demo:hover{
  xtransform: translateX(50px);
  xtransform: translateY(-50px);
  transform: translateZ(-200px);
}
.wrapper{
  perspective: 1000px;
  border: 1px solid black;
}

经验

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

#demo {
 position: absolute;
  left:50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

transform之scale

常用写法

  • scaleX( < number > )
  • scaleY( < number > )
  • scale( < number > , < number > )
  <div class="wrapper">
    <div id="demo"></div>
  </div>
#demo{
  width: 100px;
  height: 200px;
  border: 1px solid red;
  margin: 50px;
}
#demo:hover{
  xtransform: scaleX(1.5);
  xtransform: scaleY(1.5);
  transform: scale(1.5,0.5);
}

经验

用的较少,因为容易出现模糊

transform之rotate

常用写法

  • rotate( [ < angle > | < zero > ] )
  • rotateZ( [ < angle > | < zero > ] )
  • rotateX( [ < angle > | < zero > ] )
  • rotateY( [ < angle > | < zero > ] )
  <div class="wrapper">
    <div id="demo"></div>
  </div>
#demo{
  width: 100px;
  height: 200px;
  border: 1px solid red;
  margin: 50px;
}
#demo:hover{
  xtransform: rotateZ(45deg);
  transform: rotate3d(1,1,1,45deg);
}
.wrapper{
  perspective: 1000px;
}

经验

一般用于360度旋转制作loading

transform之skew

常用写法

  • skewX( [ < angle > | < zero > ] )
  • skewY( [ < angle > | < zero > ] )
  • skew( [ < angle > | < zero > ] , [ < angle > | < zero > ] )
  <div class="wrapper">
    <div id="demo"></div>
  </div>
#demo{
  width: 100px;
  height: 200px;
  border: 1px solid red;
  margin: 50px;
}
#demo:hover{
  transform: skewX(15deg);
}
.wrapper{
  perspective: 1000px;
}

transform多重效果

组合使用

  • transform: scale(0.5) translate(-100%, -100%);
  • transform: none;取消所有

实践

跳动的心

jsbin.com/rodutufona/…

心得

  • CSS需要你有想象力
  • CSS给出的属性很简单,但可以组合得很复杂

transition 过渡

作用

补充中间帧

语法

  • transition: 属性名 时长 过渡方式 延迟;例: transtion: left 200ms linear;
  • 可以用逗号分隔两个不同的属性。例: transition: left 200ms, top 400ms;
  • 可以用all代表所有属性。例: transition: all 200ms;
  • 过渡方式有: linear | ease | ease-in | ease-out | ease-in-out 等等

注意

并不是所有的属性都可以过渡

  • display: none => block 没法过渡
  • 一般改成 visibility: hidden => visible

过渡必须要有起始,一般只有一次动画,或者两次,比如hover和非hover状态的过渡

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

  • 使用两次transform
    • .a === transform ===> .b
    • .b === transform ===> .c
    • 用setTimeout或者监听transitionend事件来确定是否到中间点
  <div class="wrapper">
    <div id="demo"></div>
    <button id=button>开始</button>
  </div>
#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
    • 声明关键帧
    • 添加动画
  <div class="wrapper">
    <div id="demo"></div>
    <button id=button>开始</button>
  </div>
#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);
  }
}

使用animation时,如何将动画停在最后一帧?

加个forwards。例: animation: xxx 1.5s forwards;

@keyframes完整语法

  1. from to
  2. 百分数

ad11b4c6f0ee90808520128f030a6ca.png

animation

缩写语法

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

  • 时长: 1s或者1000ms
  • 过渡方式: 跟transition取值一样
  • 次数: 3或者2.4或者infinite(无数次)
  • 方向: reverse | alternate(交替的) | alternate-reverse
  • 填充模式: none | forwards | backwards | both
  • 是否暂停: paused | running
  • 以上所有属性都有对应的单独属性

实践

跳动的红心

jsbin.com/jatigujifa/…