一个简单的例子
将div从左往右移动
原理
- 没过一段时间(用setInterval做到)
- 将div移动一小段距离
- 直到移动到目标地点
注意性能
- 红色格子一直在重新绘制(repaint)
同样的效果用transform
原理
- transform: translateX(0 => 300px);
- transition过渡属性可以自动脑补中间帧
注意性能
- 只在开始和最后repaint
- 比改left性能好
浏览器渲染原理
浏览器渲染过程
步骤
- 根据HTML构建HTML树(DOM)
- 根据CSS构建CSS树(CSSDOM)
- 将两棵树合并一颗渲染树(render tree)
- Layout布局(文档流、盒模型、计算大小和位置)
- Paint绘制(把边框颜色、文字颜色、阴影等画出来)
- Composite合成(根据层叠关系展示画面)
三棵树
如何更新样式
一般我们用JS来更新样式
- 比如 div.style.background = 'red'
- 比如 div.style.display = 'none'
- 比如 div.classList.add('red') /直接更新类更好一点/
- 比如 div.remove() 直接删掉节点
三种不同渲染(更新)方式
- 第一种,全走
- div.remove()会触发当前消失,其他元素relayout
- 第二种,跳过layout
- 改变背景颜色,直接repaint+composite
- 第三种,跳过layout和paint
- 改变transform,只需composite
每个属性都触发什么流程: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;取消所有
实践
跳动的心
心得
- 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完整语法
- from to
- 百分数
animation
缩写语法
abination: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充模式 | 是否暂停 | 动画名;
- 时长: 1s或者1000ms
- 过渡方式: 跟transition取值一样
- 次数: 3或者2.4或者infinite(无数次)
- 方向: reverse | alternate(交替的) | alternate-reverse
- 填充模式: none | forwards | backwards | both
- 是否暂停: paused | running
- 以上所有属性都有对应的单独属性