CSS动画
前言
本文主要记录学习css动画的过程,主要讲浏览器渲染原理,translate
平移,transition
过渡,animation
动画,最后还有个小实践-跳动的💗,本文源码都有的。--资料来源饥人谷
i.动画是什么呢?
定义:
动画是一种通过定时拍摄一系列多个静止的固态图像(帧)以一定频率连续变化、运动(播放)的速度(如每秒16张)而导致肉眼的视觉残象产生的错觉——而误以为图画或物体(画面)活动的作品及其影片技术。--来自维基百科
ii.怎么写出动画效果呢?
查看动画渲染重画过程可以通过F12(或者想要查看的位置鼠标右键检查)进入开发者工具,在任意地方按esc,可以弹出一个控制台,点击控制台旁边的三个竖点(more tools),选择Rendring,勾选Paint Flashing,屏幕不断出现绿色就是浏览器在不断渲染。
- 第一种方式:
用left做动画(会经过浏览器全部步骤,浏览器渲染会介绍)
具体代码可以查看js.jirengu.com/kejop/1/edi…
可以看到方框内一直都是绿色,说明浏览器一直在渲染,repaint不断地重复画删画删的操作。--》加重了性能负担
- 第二种方式:用transform做动画* (只经过最后composite,浏览器渲染会说到)
具体代码可以查看js.jirengu.com/dukek/1/edi…
可以看到只有开始和结束时是绿的,说明浏览器并没有repaint--》两相对比说明比用left性能更👍。
iii.和动画息息相关的是浏览器的渲染
那就来了解一下浏览器的渲染吧。
参考自google团队,详细了解可以点击下面文字(查看具体链接地址可以用开发者工具查看)
1) 浏览器渲染过程
步骤:
-
根据HTML构建HTML树(DOM)
-
根据CSS构建CSS树(CSSOM)
-
将两颗树合并成一颗渲染树(render tree)
-
Layout布局(文档流、盒模型、计算大小和位置)--》"素描"
-
Paint绘制(把边框颜色、文字颜色、阴影等画出来)--》"填色"
-
Compose合成(根据层叠关系展示画面)--》"所有层拍平变成一层东西显示屏幕上"
三棵树有个图
相同节点和起来就是渲染树(render tree)
2)怎么更新样式呢?
一般用JS来跟新样式
比如div.styel.background = 'red'
div.style.display = 'none'
div.classList.add('red') *
div.remove()直接删掉节点
3)这些方式有三种不同的渲染方式*
- JS / CSS > 样式 > 布局 > 绘制 > 合成
如果修改了元素的“layout”属性,也就是改变了元素的几何属性(例如宽度、高度、左侧或顶部位置等),那么浏览器将必须检查所有其他元素,然后“自动重排”页面。任何受影响的部分都需要重新绘制,而且最终绘制的元素需进行合成。 算style,可能还要走Layout,Paint,Conposite三步合成
- JS / CSS > 样式 > 绘制 > 合成
如果修改了“paint only”属性(例如背景图片、文字颜色或阴影等),即不会影响页面布局的属性,则浏览器会跳过布局,但仍将执行绘制。
- JS / CSS > 样式 > 合成
如果您更改一个既不要布局也不要绘制的属性,比如transform,则浏览器将跳到只执行合成。
4)三种更新方式
需要用到开发者工具上面所说renderng-paint flash
- 第一种,全走
div.remove()会触发当前消失,其他元素relayout
具体代码js.jirengu.com/fewij/1/edi…
效果如下
可以看到三个方框删掉第一个空白框框后,三个框框原本位置都绿了--》证明浏览器经过了布局,绘制和合成
- 第二种,跳过layout
改变背景颜色,直接repaint + composite
具体代码js.jirengu.com/sovoq/1/edi…
可以看到效果如下
可以看到第一个方框改变颜色为红时变绿了其他没有变色--》跳过了layout,直接paint和composite
- 第三种,跳过layout和paint
改变transform,直接composite
具体代码js.jirengu.com/pabegi/1/ed…
效果如下
可以看到只有开始和结束被绘制,中间没有被repaint(重新绘制)--》直接composite
5)每个属性触发哪个流程推荐网站
要想知道哪个属性触发哪个流程除了自己试一遍别无他法,有个网站把所有属性都试过了
推荐看网站csstriggers.com/
可以告诉你每一种属性到底触发的什么流程,相同属性不同浏览器可能触发的流程不同。
iv.CSS动画优化
推荐去看google的文章里面详细讲了每个步骤的优化,太长不想看可以看TL;DR(太长不想读)。
v.transform(变形)全解
推荐看transform MDN,他会把每一个属性都给你一个列子动画,并且告诉你怎么用。
transform有四个常用的功能
- translate-位移
- scale-缩放
- rotate-旋转
- skew-倾斜
一般都需要配合transition过渡
inline元素不支持transform,需要先变成block
1. translate-移动
常用写法
translate( <length-percentage> , <length-percentage>? )
translateX( <length-percentage> )在X轴上移动,左右
translateY( <length-percentage> )在Y轴上移动,上下
translateZ( <length>)且父容器perspective(透视图原点在什么位置),在Z轴上移动,默认垂直于屏幕方向,必须要告诉视点(xyz交点)
translate3d(x,y,z)
具体代码js.jirengu.com/qiwib/1/edi…
translate(-50%,-50%)可以做绝对定位元素的居中
2. scale-缩放
常用写法
scale( <number> , <number>? )
scaleX( <number> )
scaleY( <number> )
代码演示
<head>
...
<style>
#demo{
width: 50px;
height: 50px;
border: 1px solid red;
margin: 50px;
transition: all 1s;
/*添加动画,用1s动画*/
}
#demo:hover{
transform: scale(1.5);
/*变大为原来的1.5倍*/
}
</style>
</head>
<body>
<div class="wrapper">
<div id="demo"></div>
</div>
</body>
这是有放大原来1.5倍
具体代码js.jirengu.com/waqot/1/edi…
效果如下
#demo:hover{
transform: scaleX(1.5);/*变胖1.5倍*/
/* transform: scaleY(1.5);变高1.5倍*/
/*transform: scale(1.5, 0.5); */
/*缩写,变胖1.5,变高0.5*/
}
同样也支持X,Y轴,变胖,变高。但是它的border也会相应的变形,容易出现模糊,所以一般不用scale
X: Y: XY:
3. rotate-旋转
语法格式
<rotate()> = rotate( [ <angle> | <zero> ] )
<rotate3d()> = rotate3d( <number> , <number> , <number> , [ <angle> | <zero> ] )/*太复杂了*/
<rotateX()> = rotateX( [ <angle> | <zero> ] )/*围绕X轴转动*/
<rotateY()> = rotateY( [ <angle> | <zero> ] )/*围绕Y轴转动*/
<rotateZ()> = rotateZ( [ <angle> | <zero> ] )/*围绕Z轴转动,默认就是垂直与屏幕的轴*/
代码
<head>
...
<style>
#demo {
width: 50px;
height: 70px;
border: 1px solid red;
margin: 50px;
transition: all 1s;
}
#demo:hover {
transform: rotate(45deg)
/* 默认以垂直于屏幕轴转动45度 就相当于 transform: rotateZ(45deg); */
/* transform: rotateX(45deg); 围绕X轴转动45度*/
/* transform: rotateY(45deg);围绕Y轴转动45度 */
/* transform: rotate3d(1,1,1,45deg);3d */
}
</style>
</head>
<body>
<div class="wrapper">
<div id="demo"></div>
</div>
</body>
具体代码js.jirengu.com/cicav/1/edi…
效果图如下
X轴转动: Y轴转动: Z轴转动
一般用于做360度旋转制作loading
4. skew-倾斜
语法格式
<skew()> = skew( [ <angle> | <zero> ] , [ <angle> | <zero> ]? )
<skewX()> = skewX( [ <angle> | <zero> ] )
<skewY()> = skewY( [ <angle> | <zero> ] )
具体代码js.jirengu.com/sezom/1/edi…
效果 X轴倾斜15度: Y轴倾斜15度:
transform多重效果
可以组合使用,空格隔开 例如:
#demo:hover{
transform: scale(1.5) rotate(45deg);
}
具体代码js.jirengu.com/yevux/1/edi…
效果是这样的:
放大1.5倍,并旋转45度:
vi.transition过渡
依然推荐去看transition MDN
作用
transition
作用是添加中间帧(告诉开头和结尾怎么样,中间自动补齐)
可以用代码和效果图来说明它的作用
<head>
...
<style>
#demo{
width: 50px;
height: 50px;
border: 1px solid red;
transition: width 1s;
/*如果宽度变化,就添加1s的中间动画*/
}
#demo:hover{
width: 100px;
}
</style>
</head>
<body>
<div id="demo"></div>
</body>
具体代码:js.jirengu.com/zunal/1/edi…
宽高开始,当hover时宽变为100px,transition补中间过程
语法
- transition: 属性名 时长 过渡方式 延迟(过多久开始运动)
transition: left 200ms linear 1s
- 可以用逗号分隔开两个不同属性
transition: left 200ms, top 400ms
- 可以用all代表所有的属性,上面写transform就用的all
transition: all 200ms
- 过渡方式有: linear(匀速线性) | ease | ease-in(淡入) | ease-out(淡出) | ease-in-out(缓入) | cubic-bezier | steep-start | step-end | steeps
过渡方式具体含义看MDN要靠数学知识
注意
并不是所有的属性都能过渡
display: none;=>block没法过度(从看不见到看的间没法过渡)可以用opacity: 1;=>0(透明度从1到0看不见,但位置还占着的)
如果想要从看不见到看得见一搬用visibility: hidden;=>visible
background颜色可以过渡,是16进制的
过渡必须要有起始
一般只有一次动画或者两次,比如hover状态和非hover状态的过渡。
如果除了起始还想要在中间有变化呢,中间该怎么过渡?
有两种方法:
- 一种是使用两次transform
具体代码js.jirengu.com/lejut/2/edi…
效果图
- 还有一种就是animation动画
vii.animation动画
推荐阅读animation MDN
使用animation:
- 声明关键帧
- 添加动画
#demo.start{
animation: xxx 1.5s;
/*js的点击事件后开始xxx,总时间1.5s,要想停在最后一帧,可以加上forwards*/
}
@keyframes xxx {
0% {
transform: none;
}
60%{
transform: translateX(200px);
}
100%{
transform: translateX(200px) translateY(100px);
}
}
/*给了三个关键帧,分别是0%*,60%和100%,0-60%向由移动200px,60-100%向下移动100px/
具体的代码js.jirengu.com/yojah/1/edi…
效果
可以添加任意数量想添加的中间帧,它会按照你给的线路进行移动
@keyframes完整语法
标准写法
建议搜索keyframes MDN很详细
- 一种写法是from to
- 另一种写法是百分数
from to就智能from和to
@keyframes slidein {
from {
transform: translateX(0%);
}
to {
transform: translateX(100%);
}
}
百分数更广泛
@keyframes identifier {
0% { top: 0; left: 0; }
30% { top: 50px; }
68%, 72% { left: 50px; }
100% { top: 100px; left: 100%; }
}
缩写语法
animation: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充模式 | 是否暂停 | 动画名 ;
时长: 写运动的时间。
过渡方式: 和transition取值一样,如ease。
次数: 执行的次数,也可以infinite(无限次)
方向: reverse(反方向运动),alternate(交替的,适合加载动画,过去又回来),alternate-reverse(反方向交替)。
填充模式: none | forwards(定格) | backwards(一开始就把动画第一帧复制到原始的位置) | both
是否暂停: paused | running
viii.跳动的💗
用animation做
具体代码js.jirengu.com/lesam/1/edi…
效果
你懂得
--continue
心动不如行动,学习前端从入门到入土,我正在路上。您的每一次观看,就是对我学习路上最大的鼓励,一起努力吧!
欢迎留下您宝贵的意见。