在制作一款产品时,对于用户能感知的部分,总是投入了很多精力和时间来让页面变得如何如何漂亮。可以设计最顺眼的布局,优雅的排版,美丽的图片(图标)等等的手段。
这看起来已经很完美了,但似乎还不够,此时的页面仅仅只是死的,没有活力,如果我们加入动画呢?
动画能使页面变得活泼,如果动画的加入合适,能让用户像在逛商场一样,总是充满愉快、活力的体验。
动画并非仅仅是为了好看与炫酷,她有时能暗示用户,帮助用户更好地理解你的产品。
屏幕和现实不一样,屏幕无法产生物理运动,屏幕上永远只能显示1帧
所谓的1帧,其实就是一张静止的图片,如果连续播放多张有关联的图片,那么在人眼里就造成了运动的假象,人的大脑能自动脑补出动作,一秒内播放的帧越多,画面就会显得越流畅。
在开始讲解之前,务必要先给你讲讲核心原理,就如你是一个汽修修理工,总得先知道一个概念
汽车之所以能动,是因为里面有个马达。
css里的动画,其实很多情况下,都是在几个关键帧之间转换(帧动画),或者说几个数值之间变化(补间动画)
如这个例子:
你观察一下上方这个长方形的变化,你会发现,只是高度在变化,变到最高和最低
确实是这样的
@keyframes aa{
0%{
height: 0px;
}
100%{
height: 200px;
}
}
0%的时候高度是0px,100%的时候是200px,我只指定了关键值,关键的两个数值,浏览器便能动态变化了。
举个不恰当的例子:
你爸爸此时正在家看金碟豹,对一旁的你说:去商店给我买包烟
此刻的你在家,而你爸叫你去商店,这是两个不同的地点,但你却能顺利地从家前往商店,并从商店再返回家。
这是为什么?因为你知道沿着某条路一直走便能走到商店,从商店回来也是同理。
而你给的初始值是0px,最终值是200px,计算机自然也能计算0px到200px之间的值。
这用专业的词叫:补间动画,补间,计算机补的就是中间的值,一种状态平滑变到另外一种状态。
所以你现在必须脑海中得有一个概念:只要设置好关键的值,计算机便能给我生成连贯的动画效果
再举个例子:
就像50米赛跑,有起跑点和终点,裁判规定好起跑点和终点,而运动员是不是就能自觉地从起跑点跑到终点了?
而你此刻就是那个裁判,你指定好起跑点和终点,而浏览器就能自动帮你从0米一直跑到50米
而你这个裁判更离谱,你还能控制这人50米什么时候开跑,跑几遍,在多少时间内完成等等命令。
而浏览器就相当于那个选手,只能受你摆布,老老实实按照你的命令跑步(这不就是程序员?)。
补间动画,浏览器能补哪些呢?高度、颜色、角度、坐标、透明度…等等都能补
下面这个例子变了颜色,我指定了三个关键的颜色(三个关键的值):
@keyframes aa{
0%{
background: red;
}
50%{
background: green;
}
100%{
background: blue;
}
}
你看浏览器就能自动用这三个颜色,不生硬很平滑地变化了。
在日常开发中,一般会借由两种方式产生所谓的动画
transition:一般叫过渡,需要事件触发(不是JavaScript里的事件),比如:hover,鼠标移上去就触发,只能设置两个关键值,初始和结束。
animation:这个叫动画,不需要事件触发,写好了就能执行,操作有很多(下面重点会讲),可以设置相当多的关键值(关键帧)。
虽然大家叫过渡,但也是属于能动的,顺便也讲了。
先来一个例子:
左边第一个矩形关键代码很简单:
div {
background: red;
}
div:hover {
background: blue;
}
div刚开始是红色的,当鼠标移入之后,就里面变为蓝色
这看起来功能挺正常的,但看着似乎有些生硬了,红色变为蓝色这个过程,是瞬间完成的,很是突兀。
如果加上 transition属性
div {
background: red;
transition: 0.4s;
}
div:hover {
background: blue;
}
现在你把鼠标移入第二个红色盒子,颜色的变换就变得比较自然了,因为浏览器自动给你补全了红色到蓝色之间的颜色,当存在连续变化(线性)之后,看起来就像在动一样,比较理所当然。
浏览器为何能补全两个颜色?颜色其实也是数值,在css里面,可以通过特定的英语单词来描述,比如:red、green、blue、orange之类的。
还可以通过以下方式:
十六进制表示颜色:#ff0000
RGB表示颜色:rgb(255,0,0)
HSL表示颜色:hsl(360,50%,50%)
四种方式,看你喜欢,我一般爱用十六进制。
transition有一些子属性:
属性 | 值 |
---|---|
transition-property | 动画展示哪些属性,可以使用all关键字 |
transition-duration | 动画过程有多久 |
transition-timing-function | 控制速度变化 |
transition-delay | 动画是否延迟执行 |
transition-property:你的哪个部位变了,你就填哪个,像上一个例子中,只有颜色变了,
所以transition-property:color;
就行了,高度变了就填高度,如果有多个变了,可以加入逗号,比如
transition-property:color,height;这里代表着颜色和高度有变化,也可以直接填入all,表示全部。
相当于是一个检测器,当检测到填入的属性变了,就给加过渡效果,如果填入的是color,哪天color的值变了,就会给你整个过渡效果,如果哪天高度变了,那抱歉了,没有过渡效果,因为transition-property里没指定高度。当你填入all时,但凡有点风吹草动,都加入过渡效果。
transition-duration:填入时间,单位是秒,比如:transition-duration:0.4s
,表示动画时常只有0.4秒。
也可写成transition-duration: .4s,小数点前的0可以省略。
transition-timing-function:动画的速度变化,比如大家常说的九浅一深
,先快后慢再贼快之类的,css内部提供了一些英语单词:linear,ease,ease-in,ease-out,ease-in-out;也可以用贝塞尔曲线函数cubic-bezier()控制动画的速度变化。
transition-delay:等待一下,再执行动画,比如:
transition-delay:2s;
等两秒才执行动画。
这四个单独的属性,是可以组合在一起写的
transition-property:width;
transition-duration:5s;
transition-delay:2s;
/*组合,一句话完成*/
transition:width 5s 2s;
写的时候,可以问自己transition:哪个变?变多久?怎么变?等多久变?
日常开发中,如果不是有特殊的需求,往往我们在写的时候,只会写第一个和第二个,也就是哪个变和变多久
比如:transition: width 5s;
我只写了个宽度变和变五秒,其他属性可以不写,因为浏览器会给默认值。
先看看整体大概结构:
div {
animation: wch 3s;
}
@keyframes wch {
0% {
color: #000;
}
100% {
color: #fff;
}
}
animation: change 3s;是动画的第一部分,用来控制动画的各个规则,比如:延迟、次数、时间等等,上面这个代码中指定了动画效果和时长。
@keyframes wch{…}是动画的第二部分,里面主要是写动画各个关键值(关键帧),是以百分比的形式,你可以理解为一个进度条,走到0%了执行某某某,走到23%了执行某某某,走到50%了执行某某某,走到100了执行某某某。
和上面的过渡属性transition一样,浏览器都能给你在每个关键帧中间生成平滑过渡效果,如上方0%时是#000(黑色),一直到100%时的#fff(白色),这之间的变化是由浏览器自动生成的(你不用纠结他是根据什么原理生成的)。
animation的子属性有:
属性 | 值 |
---|---|
animation-name | 指定由 @keyframes 描述的关键帧名称。 |
animation-duration | 设置动画一个周期的时长。 |
animation-delay | 设置延时,即从元素加载完成之后到动画序列开始执行的这段时间。 |
animation-direction | 设置动画正向运行还是反向运行等等 |
animation-iteration-count | 设置动画重复次数, 可以指定 infinite 无限次重复动画。 |
animation-play-state | 允许暂停和恢复动画。 |
animation-timing-function | 设置动画速率,比如先快后慢 |
animation-fill-mode | 指定动画执行前后如何为目标元素应用样式。 |
@keyframes 规则 | 设定关键帧 |
其中,对于一个动画:
必须项:animation-name、animation-duration 和 @keyframes规则
非必须:除上面三个,其余的都有默认值,可以不写
下面开始详细讲解各个属性
animation-name的作用,只是和@keyframes 规则绑定的,让浏览器把你写的animation和@keyframes对应上
div{
animation: bb 2s;
}
@keyframes aa{
0%{
background: #000;
}
100%{
background: #fff;
}
}
@keyframes bb{
0%{
background: #000;
}
100%{
background: #fff;
}
}
这里的div里的动画,会去找bb那个,而不会去找aa,有的时候一个页面要写很多组@keyframes 集合,肯定要用名字区分一下谁是谁。
animation-duration的作用是设置动画时常,上方代码中,设置的动画时长是两秒,这个属性单位是秒。
延时,也就是等多久才执行,延迟几秒执行,直接看效果:
第一个长条立马冒出了,第二个等了一秒才开动。
核心代码:
<div></div>
<div></div>
div{
animation-name: aa;
animation-duration: 2s;
}
.vv{
animation-delay: 1s;
}
@keyframes aa{
0%{
width: 0vw;
}
100%{
width: 100vw;
}
}
上面这个小代码,其实可以用一句话表示,用熟练了其实不用单独写animation的子属性了,可以全部写在一起:
animation: aa 2s 1s
表示为:动画的名字、时长、延时
动画的延时,时长可以填入负数,时间可以用负数来表示吗?其他地方也许不行,但在css的动画里,是可以的。
填入负数时间表示的含义为:提前x秒执行
举个例子,还是上边那个五十米跑步,裁判在喊开始的前五秒的时候,你就开跑了
我假设每个运动员的速度一样,都是一秒跑10米
当裁判正式喊跑的时候,你是不是已经领先其他选手50米了?
其实,时间是不会提前的,那浏览器怎么表现出这个动画是提前执行的呢?
假设现在我们要在2秒内,从1一直变到200,正常情况下,就是老老实实的从123456789一直到200,这个过程持续两秒
如果我提前1秒变呢?从客观上看,其实我根本没有提前,只是在动画开始执行的时候,我不是从0开始数的,我是从一秒那时刻开始数的,1数到200需要花费2秒,那在一秒的时刻,正常数,是100,那么我就是从100那开始数的。
可能讲的不是很好,再换个例子,我和我弟弟需要前往学校,需要经过A、B、C、D才能到,学校七点半上课。我那弟弟喜欢七点整点出发,而我起得早,我六点半就出发,弟弟走到A的时候,而哥哥我已经走到C了,而浏览器是站在我弟弟的视角的:我才出发,这哥哥怎么就瞬间变到C点了?
来个实际例子:
如果你想实现这个效果,有两种思路
第二种思路开始实施了:
.qiu1 {
animation: rotate 3s infinite linear;
}
.qiu2 {
animation: rotate 3s infinite 1s linear;
}
.qiu3 {
animation: rotate 3s infinite 2s linear;
}
上述代码表示的意思为:动画名字叫rotate 动画时长3秒 动画次数无限 动画速率是匀速
代码中的infinite表示动画无限循环,linear表示动画是均速的,下面会讲。
动画效果不太对,动画一开始时,三个球没有一起动,只有等了两秒后,三个球才一起在动。
现在我们用到负数的延迟吧:
.qiu1 {
animation: rotate 3s infinite linear;
}
.qiu2 {
animation: rotate 3s infinite -1s linear;
}
.qiu3 {
animation: rotate 3s infinite -2s linear;
}
当第一个球开始动的时候,第二个球已经提前跑到120度的位置(提前一秒),而第三个球由于是提前两秒,则早就跑到240度的位置了,所以当第一个球开始动的时候,此瞬间,三个球的夹角已经变成了120度,是我们想要的效果,已经变成我们想要的形状了。
值得一说的是,第二个第三个球,写了提前x秒执行,其实压根就没有提前执行,这里说的提前,实际上只是瞬间移动到了x秒的位置,动画效果是没有提前执行的,只是数值跑到了x秒的数值去了,所以在我们的眼里,他是瞬间出现在那个位置的(至于为什么说提前,那是先对于0秒来说的,我才开始掏出作业本,你就要抄完了,你是不是提前偷抄了?)。
正常:123456
提前两个数:3456
控制动画的速率,是先快后慢,还是先快一点再慢一点最后再快一点还是…
正规的说法是:它定义了动画在每一动画周期中执行的节奏。
css官方支持一些特殊的英文单词参数:
这里就不演示效果了,直接放张图:
除了这五个关键字外,还支持三次贝塞尔曲线,用 cubic-bezier()方法,比如:
animation-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
贝塞尔曲线,网上有现成的工具生成:点击访问,有了贝塞尔曲线,就可以为所欲为了,不局限于官方提供的五种速率。
网上有个很直接的例子:点击访问,可能需要科学上网
animation-timing-function除了内置五个速率和贝塞尔曲线的方法外,还内置的一个函数:steps函数
这个函数,一般拿来做逐帧动画,也就是这种:
这北极熊在跑,跑的这个动作,其实是由八个单独的姿势组成的。
当连续播放的速度够快,就能造成一种视觉上的连贯性。
假如我们有下面这种图片:
我该怎么做才能让这小人动起来呢?
而steps函数是将整个动画过程分为指定的步数,举例的话:
大富翁,摇塞子走格子,摇到6就一格一格地跳6格
假设我写了一句:steps(6)的意思就是将设定的 @keyframes 动画分为 6 段执行,而整体的动画时间是
0.6s
,所以每一段(这里也可以理解为是每一帧)的停顿时长为0.1s
;
拿上面那个小人来说,通过观察,我们知道,小人的动作被分为了6种姿势,我们如果用steps(6)把动画分成6次6帧,而每帧如果刚好对应上图的一种姿势,那是不是就把这小人的6种姿势给连贯起来了?
<div></div>
div {
width: 256px;
height: 256px;
background: url(./sprite.png);
background-size: cover;
background-position: 0px;
animation: sprite 0.6s steps(6) infinite;
}
@keyframes sprite {
0% {
background-position: 0 0;
}
100% {
background-position: -1536px 0;
}
}
用文字可能不是很好叙述,我录制了一个视频
这个属性很显然,控制动画运行和暂停的,
它能填的值有两个:paused和running,默认情况下是running
上面这个小例子,鼠标放到文字上,方块就能停下
核心源码:
<div class="aa">停!</div>
<div class="bb"></div>
<style>
.bb{
animation: move 2s infinite alternate;
}
@keyframes move {
100% {
transform: translate(100px, 0);
}
}
.aa:hover + .bb {
animation-play-state: paused;
}
</style>
控制元素在各个阶段的状态,各阶段?CSS动画都有哪些阶段?
animation-fill-mode有四个选项:none、both、backwards、forwards
none 表示 等待期和完成期,元素样式都为初始状态样式,不受动画定义(@keyframes)的影响。
both 表示 等待期样式为第一帧样式,完成期保持最后一帧样式。
backwards 表示等待期为第一帧样式,完成期跳转为初始样式
forwards 表示等待期保持初始样式,完成期间保持最后一帧样式。
可能有点不好理解,下面我用视频来讲解一下:
(如果你懒得看视频,你也可以直接看网上的一篇文字攻略,点击访问,我就是在这领悟的)
我个人的理解:这个属性主要用来控制元素在运行这个动画之前和之后的事
执行动画之前如何?
执行完动画之后如何?
这两个一起讲,
animation-iteration-count,填入数字就代表动画执行几次,填入infinite则会一直执行,如果不指定默认动画只执行一次
animation-direction,默认是正向播放,也就是从0%一直到100%;若是填入reverse
,动画则会先从100%然后再慢慢地执行到0%。
至于所谓的正反交替,也很好理解:
你从家到学校,
然后从学校返回家,日复一日
从家到学校类比为:从0%到100%,
从学校返回家类比为:从100%到0%
这就是一次正反交替
在有的时候,如果你的动画没有写正反交替,会造成一个现象:当动画执行到100%之后,瞬间就变到0%了,这个过程是瞬间完成的,会让用户感到很僵硬。
下方这个小例子,第一个红条,每次都在100%时瞬间变成0%;而第二个红条,跑到100%之后会慢慢变0%,然后又再从0%变到100%,给人一种过渡平滑的感觉。
alternate-reverse表示反正交替,也就是先从100%到0%,在从0%到100%
还是列出官方的说法吧,免得你的理解和我产生偏差了:
属性 | 值 |
---|---|
normal | 默认值。动画按正常播放。 |
reverse | 动画反向播放。 |
alternate | 动画在奇数次(1、3、5…)正向播放,在偶数次(2、4、6…)反向播放。 |
alternate-reverse | 动画在奇数次(1、3、5…)反向播放,在偶数次(2、4、6…)正向播放。 |
假设我们要实现这么一个效果:
黑色方块,有下滑的动画,也有透明度的变化
我希望你在实现的时候,多写几组keyframes,如:
div {
animation: falldown 2s, fadeIn 2s;
}
@keyframes falldown {
100% {
transform: translate(0, 150px);
}
}
@keyframes fadeIn {
100% {
opacity: 0;
}
}
建议别把一堆变化全写在一个@keyframes来实现动画效果,这个例子还好,如果你未来的动画很复杂,这将变得难以梳理。各个分开写,可以做到对每一个属性动画做到精准的控制。
一个标签是可以指定多个@keyframes的。每个动画直接用逗号连接
如果你想把animation的各个子属性全写在一行,先后顺序为:
animation: name duration timing-function delay iteration-count direction;
名字 时长 速率 延时 次数 方向
/*比如:*/
animation: wch 5s infinite;
/* 用不到的子属性可以不写,浏览器会给默认值 */
使用百分比:
@keyframes wch {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
使用英文字符:
@keyframes wch {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
在写英文字符时,from
等同于 0%
,而 to
等同于 100%
。
如果你的动画不止两帧,还是用百分比的形式吧。
如果你认认真真学了这一篇CSS动画之后,希望你不要产生学完之后就能立马做出各种很炫酷的特效的想法
这里并没有否非花哨的效果,只是因为做出这种花哨的效果不容易
做动画也是做设计,这需要一定的想象力,这似乎要看个人了,我觉得没经过培养的普通人的灵感应该没那么变态吧?
其次就是技术,你得非常了解CSS的各种属性;还得具备一些格外的技能,比如有时还要借由错觉,想方设法欺骗观众的眼睛之类的,这种非CSS方面的技能。
这些都需要慢慢积累的,一时做不出也无妨,慢慢来,别一来就分析别人复杂的动画,给自己添堵,懂得循序渐进。想制作出让人赏心悦目的页面,讲究一个合适观感。好比是一个班级,成绩最好的那位同学全年级第一,但学生的整体水平却不咋地,这能体现出一个老师的授课水平吗?
说到底动画效果只是辅助,属于锦上添花,页面观感或者功能不咋地,就算加入很炫酷的动画,也只是属于屎盆子镶金边,东施效颦罢了。
当然这只是我的一家之言,我并非专业的人,这只是我结合我的见闻而得出的结论。
看完这篇CSS动画文章后,也莫局限于CSS,JavaScript也可以做出好看的效果,不一定非得用CSS里transition和animation。
这篇文章参考了知乎上的大佬点击访问、菜鸟教程、CSDN、segmentfault等等,
写完这篇文章,使我对CSS里的这俩动画属性有了更深的认识了,特别是某些属性,从陌生到现在认识。这篇文章算是我写过目前来说应该算是篇幅最长的一篇了。
文章中的例子,我都提供了源码点击查看,在学习的时候,可以用我的源码进行调试,知其然,知其所以然。
你的想法与我的表达有时难免同步(这很正常,每个人思考的角度和侧重点可能不一样),如果有疑问,评论区留下你的疑惑,文章中如有错的欢迎批评指正,有好想法也可以评论区交流。