浅谈CSS3 动画从2d到3d

1,147 阅读9分钟

一、transition

transition 属性设置元素当过渡效果,四个简写属性为:

描述
transition-property指定应用过渡属性的名称
transition-durationtransition效果需要指定多少秒或毫秒才能完成
transition-timing-function指定transition效果的转速曲线,值有:linear、ease(默认)、ease-in、ease-out、ease-in-out、cubic-bezier(n,n,n,n)
transition-delay定义transition效果开始的时候

1. transition-property

transition-property 指定应用过渡属性的名称。它的默认值为:all。 属性值虽然可以CSS全属性,但是很多属性是不生效的,而且有的属性需要在特定的时候才能生效。 例如height属性,需要给初始值与结束值给到高度,否则不会产生过渡效果。

2. transition-duration

transition-duration 属性规定完成过渡效果需要花费的时间(以秒或毫秒计)

.box {
    transition-duration: 5s;
}

3. transition-timing-function

描述
linear规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。
ease规定慢速开始,然后变快,然后慢速结束的过渡效果(cubic-bezier(0.25,0.1,0.25,1))。
ease-in规定以慢速开始的过渡效果(等于 cubic-bezier(0.42,0,1,1))。
ease-out规定以慢速结束的过渡效果(等于 cubic-bezier(0,0,0.58,1))。
ease-in-out规定以慢速开始和结束的过渡效果(等于 cubic-bezier(0.42,0,0.58,1))。
cubic-bezier(n,n,n,n)在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值。

各个值的效果如下:

緩动动画速查网: cubic-bezier.com/

4. transition-delay

transition-delay 属性规定过渡效果何时开始,允许为负值。

5. 简写

语法:

transition: property duration timing-function delay;

例如: codepen.io/jianxiujiuc…

.box {
    transition: width 1s ease-out .5s; 
}

注意:很多同学写的时候也会写成:

.box {
    transition: all 1s; 
}

all 表示的是所有的属性都进行过渡。如果有的属性并不需要过渡效果(比如有的按钮hover,只需要背景过渡,文字不需要过渡),那么还是针对想要进行过度的属性进行设置为好。

如果需要进行多属性进行过渡,则用逗号隔开,例如:

.box {
    transition: width 1s ease-out .5s, height 1s ease-out .5s; 
}

二、animation

描述
animation-name规定需要绑定到选择器的 keyframe 名称。。
animation-duration规定完成动画所花费的时间,以秒或毫秒计。
animation-timing-function规定动画的速度曲线。
animation-delay规定在动画开始之前的延迟。
animation-iteration-count规定动画应该播放的次数。
animation-direction规定是否应该轮流反向播放动画。
animation-play-state指定动画是否正在运行或已暂停

1. steps()

animation-timing-function 除了和transition-timing-function有相同的属性之外,还多了一个steps()steps()属性允许我们将动画或者过渡分割成段。 其实就是拆成多个均等的逐帧动画,在相应的时间里执行。 语法:

steps(int, start|end)

steps接收两个参数,前一个是正整数。后一个可选两个值,startend,表示动画是从时间段的开头连续还是末尾连续。

区别如下:

【DEMO】:steps2个参数之间的区别

我们常见的gif图片就是逐帧动画图片,每一帧依次执行,GIF如下。

bird.gif

gif图片用PS打开并调起时间轴面板,会发现这张GIF图有12张帧图片。循环执行它就能得到gif动画。

帧.png

常规做法,写12个帧动画,然后用background-image改变它到每一帧的图片(也可以合雪碧图改变它的background-position):

@keyframes bird {
  @for $i from 1 through 12{
    #{$i / 12 * 100%}{
      background-image: url("#{$i}.png");
    }
  }
}

SCSS看起来没几行,感觉还挺好的。但是我们看看生成css的代码:

@keyframse bird{
  8.33333% {
    background-image: url("1.png");
  }
  16.66667% {
    background-image: url("2.png");
  }
  25% {
    background-image: url("3.png");
  }
  33.33333% {
    background-image: url("4.png");
  }
  41.66667% {
    background-image: url("5.png");
  }
  50% {
    background-image: url("6.png");
  }
  58.33333% {
    background-image: url("7.png");
  }
  66.66667% {
    background-image: url("8.png");
  }
  75% {
    background-image: url("9.png");
  }
  83.33333% {
    background-image: url("10.png");
  }
  91.66667% {
    background-image: url("11.png");
  }
  100% {
    background-image: url("12.png");
  }   
}

这代码也太多了,如果图片有个几十帧那岂非一大堆代码。

所幸还有steps()这个王炸属性。我们可以用它来实现这一动画效果。

首先我们需要把所有的帧图片合成一张雪碧图,合成之后的图片如下:

(推荐一个合雪碧图的网站:sprite-generator

bird.png

然后我们编写代码:

.bird {
    width: 120px;
    height: 120px;
    background: url(bird.png) no-repeat;
    animation: bird 1s steps(12) infinite;
  }

  @keyframes bird {
    0% {
      background-position: 0 0;
    }
    100% {
      background-position: -1440px 0 ;
    }
}

得到的效果就如gif图展示一致。而且时间可以自己控制。

steps()写两个小动画:

数字帧: 【DEMO】:数字帧动画

时钟效果: 【DEMO】:摆钟

2. 比较不常见的知识点

2.1. animation-duration 可以为负数,比如
.box{
    animation: move 2s -1s; // 相当于已经执行1秒后的效果
}

利用负数的属性,我们可以用来完成一些“你追我赶”的动画效果:

比如这个常见的Loading动画,如果延迟没有设为负数,刚一开始的动画会先这停顿,再有序执行 无延迟.gif

如果延迟设为负数,则可以由始至终都是有序进行。

【DEMO】:设置时间负数对比动画

2.2. 想要执行多个动画效果,可以用逗号叠加写,如:
.box {
    animation: fadeIn 1s, fadeOut 1s 1s; 
    //执行完显示效果fadeIn 1秒之后,执行隐藏效果,隐藏效果过程为1秒
 }

【实战】:多动画叠加

2.3 如果两个动画属性及时间是有冲突的,则会直接执行下一个动画。比如:
animation: fadeIn 1s, fadeOut 1s; //直接执行fadeOut
2.4 如果两个动画属性有冲突,但是时间是完全错开的,则可以依次执行。
animation: fadeIn 1s, fadeOut 1s 1s; //执行fadeIn结束再执行fadeOut
2.5 如果两个动画属性有冲突时间不完全错开,则执行第一个还未完成时,第二个时间到了就会执行,第一个动画失效。例如:
.box {
    animation: fadeIn 1s, fadeOut 1s .5s;
    //执行完显示效果fadeIn 0.5秒(本应为1秒)之后,执行隐藏效果,显示效果执行。
 }
2.6 如果你非要想有冲突的动画属性都能生效,那么请多嵌套一层,外层写一个动画,内层写一个动画即可。
.box {
    animation: ....
    .inner{
        animation: ....
    }
 }

三、动画核心属性

1. transform

1.1 旋转 rotate

rotate2d旋转有三种方式,rotateX()、rotateY()、rotateZ(),括号里的数值为角度。

  • rotateX(),沿着X轴转,就像路边摊卖的烤鸡一样。

http_______mmbiz.qpic.cn___mmbiz_jpg___lkoeefVduXuWVeC69DiaAsRlgMsDkJrPNF5YZAyv28zyQsSNeIuofg60vK7R69OoM3BeveJ6L59FPlSNJLnI7qg___0_wx_fmt.jpeg

  • rotateY(),沿着Y轴转,就像土耳其烤肉一样。

turkish-g5ab7206f5_640.jpg

  • rotateZ(),沿着Z轴转,就像风车转一样。

small4_15823608132833997.jpg

rotate3d旋转,语法为rotate3d(x, y, z, a),可同时对于三个轴进行旋转。例如:

rotate.gif

【DEMO】: rotate

(为啥看起来怪怪的,没有立体的效果?下边讲到3d的时候会讲到。)

1.2 偏移 translate

translate也有三种方式:translateX、translateY、translateZ。

  • translateX:左右偏移
  • translateY:上下偏移
  • translateZ:前后方向偏移,需要配合透视属性prespective才有效

【DEMO】:translateZ效果

1.3 斜切 skew

skew有两种方式:skewX(x)、skewY(y),二者共存可简写为skew(x,y)。

skewX(x):参数x表示元素在x轴方向的倾斜度数,单位为deg。如果度数为正,则表示元素沿x轴方向逆时针倾斜;如果度数为负,则表示元素沿x轴方向顺时针倾斜。

skewY(y):参数y表示元素在y轴方向的倾斜度数,单位为deg。如果度数为正,则表示元素沿y轴方向顺时针倾斜;如果度数为负,则表示元素沿y轴方向逆时针倾斜。

skew.png

1.4 矩阵 matrix

matrix其实是可以代替:偏移量(translate),缩放(scale),斜切(skew),旋转(rotate)这四大属性的,任意一个matrix样式改变而来的形状也都能通过以上四个功能实现,它们是互通的。 详细分解可参考:

理解CSS3 transform中的Matrix(矩阵)-张鑫旭

1.5 transform-origin

transform-origin,官方解释为设置旋转元素的基点位置。其实就是设置元素的变形原点。

如果有熟悉PS的小伙伴就很好理解,当我们Ctrl+T要变形的时候,再按下Alt键,就看到图片中间有一个点,这个与CSS是一致的,都是在中心的位置。 这个原点可以拖动,拖动到哪个位置,元素就在哪个位置进行变形。

Ooo1.gif

css的变形原点也是一样,希望在哪个位置进行变形,设置 transform-origin就可以了,它可以是百分比,可以是具体的数值,也可以是left right top bottom center这样的关键词。

【DEMO】:transform-origin

1.6 transform-style

transform-style有两个值,flatpreserve-3d。这个属性是要设置在父元素上的,它将会影响子元素的展示方式。 默认的值为flat,表示的是子元素在2D空间中呈现。设置为preserve-3d则子元素在3D空间中呈现。 我们可以利用这一属性,绘制一个立方体。

【demo】:仿webpackLOGO立方体动画

2. prespective

perspective是透视的意思,指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。 z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定。如图所示:

css3d-z-scroll-perspective1.png

当一个平面元素,加上了透视属性,就会有立体的效果,如下图所示:

透视

【DEMO】:透视效果

perspective属性有两种书写形式,一种用在父元素上;另一种用在当前元素上,作为transform的值。如下代码示例:

.box {
  perspective: 500px  
}
.inner{
    transform: rotateY(60deg)
}

如果有只有一个元素,那么效果等同于:

.inner{
    transform: perspective(500px) rotateY(60deg)
}

如果有多个元素,那么效果区别就很大了。我们来看例子:

【DEMO】:perspective两种写法的区别

所以上面的2d动画,在我们加了perspective属性之后,就有立体的效果了。

【DEMO】:立体效果

【DEMO】:透视效果-立方体

有了透视属性,再加上变形效果,我们可以用CSS实现3d全景看房。

【DEMO】:CSS全景看房

3. backface-visibility

backface-visibility 属性定义当元素背面向屏幕时是否可见。

【DEMO】:backface-visibility 从例子中可以看到,如果元素旋转到背面,那么该元素就不可见了。 我们可以使用这个特性制作翻牌的动画:

【DEMO】:翻牌效果

从这个动画可以延伸出一个3d墙翻牌的动画:

【DEMO】:卡片动画

==================================================================

4. CSS3动画欣赏:

  1. 有趣的404
  2. 时空隧道
  3. 旋转的楼梯
  4. 立体书