无立体,不动画,CSS3 3D 动画属性入门

关于CSS3 3D Transform是变形属性里面的战斗机,就像立体几何的学习要在平面几何以后相似,在关于全部的2D的属性摸个七七八八以后,终于开始进阶3D变形了。先来一张SVG的背景图。炎炎夏日,清凉一下,即便不能行万里路,至少还有心在远方。 算法

对于2D方向的移动,已经乏善可陈了,一个transform:translateX() 或者transform:translateY() 就能轻松实现水平和垂直方向的移动。那咱们都知道,3D空间多了一个Y轴维度,4D空间多了一个时间维度,5D空间多了……就此打住,本篇不讨论科幻。(此处插播一本小说《平面国》,2D维度的世界,也比较有趣。)言归正传,显示屏展示了二维平面,那把Z轴想象成你和显示屏之间的一个距离轴线。既然如此,那transform:translateZ()是否是就能实现Z轴维度的移动了呢?你想多了。毕竟从2D到3D也是一个量变,岂能辣么简单? 浏览器

1.关于容器和透视属性

先简单来讲一下浏览器实现3D效果的原理,各类坐标轴什么的就不班门弄斧了,毕竟一搜一大堆。SVG向浏览器宣告“我要使用3D效果啦,作好准备”就要传递一个信号,只有translateZ是不够的,浏览器须要有一个准则,就是沿Z轴移动的比例是什么?换句话说,须要设置一个透视点perspective来配置3D空间,也就是CSS的perspective属性,再直白点说,就是咱们的眼睛距离屏幕(Z轴)的距离。那perspective属性应该对谁定义呢?舞台,或者说是SVG的父容器。好比说,我定义了沿Z轴移动的动画cubic以下:bash

@keyframes cubic{
0% {transform: translateZ(0)}
100% {transform: translateZ(-300px)}
}
.cubic {animation:cubic 2s ease;}复制代码

做为图片而存在的SVG是没有perspective属性的,它的父容器是什么?咱们都知道,SVG里面的标签,<path>也好,<circle>也好,都是一些绘制方法,<g>也只是进行了组合,并不是真正的父容器,这时,纯SVG有些无力了,那咱们就把它放到一个<div>里,来实现这种3D效果。既然“在我地盘这儿那就得听个人”,下面就来定义这个霸气的地盘(或者称之为舞台)透视属性。svg

.stage {
perspective: 200px; 
background:#e5fffb; /*给舞台定义一个浅绿背景色*/
}复制代码

<body>代码部分就简单多了,只须要<div>里嵌套这个<SVG>就OK了。学习

<div class="stage">
<svg class="cubic" xmlns="http://www.w3.org/2000/svg" width="800" height="600">
<g>
…此处省略若干组成SVG图形的代码
</g>
</svg>
</div>复制代码

来检验一下效果如何动画

是否是有些失望?这明明就是缩放效果好不啦?我要你?明明一个transform:scale()就能搞定!掀桌子,抗议,停停停,说过Z轴是眼睛和屏幕间的轴线,沿Z轴移动可不就是缩放嘛。人家但是用二维的表现来营造观察者离屏幕移动的的场景啊(你还想怎样,难不成让图片从屏幕里出来,像贞子同样?)。 spa

2.透视属性与变化

这里关于perspective属性值咱们先定义几个极值看一下,第一个,我定义perspective:1000px,效果以下:3d


在一样translateZ状况下,感受变化很小。

第二个,我定义perspective:1px,效果以下:code


在一样translateZ状况下,变化灰常剧烈,缩成了一个点。

为了好理解,咱们先假定地心说,宇宙万物绕着地球转。请看下图(原谅我不会3D建模,好忧桑)orm


左边那个场景咱们想象成一个小人以45度角仰望天空,一轮明月悬空高挂,右边那个场景咱们想象成一个小人头上不远的地方挂了个大南瓜吧。在视觉上,明月和南瓜是同样大小的。此时,当太阳向小人方向移动2米,小人彻底看不到这种移动,但南瓜往脑壳方向移动2米,只见愈来愈大,个人妈呀,这是要砸下来了。因此一样的移动距离,因为视距不一样,产生了差别。正所谓近大远小,也就是说 perspective值越大,表明观察者离屏幕越远,那一样 translateZ的移动距离,在视觉上呈现的效果越明显。

由于我把translateZ定义成了负值,就是背离眼睛方向(眼睛→屏幕),因此愈来愈小,那当我改一下,transform: translateZ(300px),让Z轴移动为背离屏幕状况下又是怎样的呢?


喷薄欲出,这就是南瓜砸脑壳的效果吧。

再延伸一下,当perspective为0时,会是什么效果呢,沿Z轴正向移动时,大到无极限,沿Z轴负向移动时,小到看不见?不,此极值至关于眼睛贴到了屏幕上,恭喜你,这是进入了二维世界,因此Z轴的移动对于二维平面来讲,是没有变化的。这也就是为何咱们perspective不定义(默认为0)时,没有效果的缘由。

3.关于透视原点perspective-origin

全部的变形动画都有一个原点(不定义,不表明没有,一般是默认值),这在tranform:rotate选择动画中表现最为明显,咱们会常常定义变形原点tranform-origin来肯定元素动画效果的基准点。对于咱们3D动画属性来讲,就要增长一个相似的概念,透视原点perspective-origin。若是说perspective值表明眼睛离屏幕的垂直距离,那perspective-origin则表明了上下左右晃动脑壳后再去观察,此动做是二维平面的动做,所以perspective-origin属性包括两个值,一个与水平X相关,一个与垂直y相关当缺省时,默认为(center center)仍是上面的Z轴移动效果,来试一下改变perspective-origin属性值会发生什么。以下,我给父容器增长一个透视原点的属性值

.stage {
perspective: 200px; 
background:#e5fffb; 
perspective-origin: left  top; 
}复制代码

沿Z轴移动就变成了下面这个样子:


其余属性值就再也不一一尝试了,大概也能猜个七七八八,这里除了left right top bottom center这种直接写法,还支持百分比的表示方法。感兴趣能够自行尝试。

4. 3D旋转动画

沿Z轴移动这种效果,别说众位看官没有兴趣,我也觉索然无味,单纯的移动能够靠2D的一些属性来完成,接下来试个稍微有趣点的效果,3D空间的旋转。在2D平面上的旋转transform:rotate(),是点旋转,这里的点,是指在平面上绕的点,而3D空间的旋转,则是轴旋转。绕X轴或Y轴,因此咱们要把属性写成transform:rotateX()或transform:rotateY()这样子。
如今从新定义一下动画属性,先来个绕X轴旋转45度:

.cubic {animation:cubic 2s ease}
@keyframes cubic{
0% {transform: rotateX(0)}
100% {transform: rotateX(45deg)}
}复制代码

获得的动画效果:

从效果里能够明显的看出,首先,旋转方向的定义,正值是向屏幕内部旋转,若是这么说没有空间感的话,也能够理解成在Y和Z组成的平面(即与X轴垂直的平面)以笛卡尔坐标系X轴正值方向观察为顺时针旋转。算了,太别扭了,仍是来张3D坐标系的图解释一下。

从动画效果里咱们会发现一个奇怪的现象,就是SVG底图——变!虚!了!说好的矢量图形无限放大呢?由于不懂算法渲染什么的,我的猜想浏览器在处理这类3D效果时,先绘制了一张位图,而后以位图为蓝本进行处理,好吧,我在胡扯,具体缘由等查到相关资料再更正。

改几个角度看一下,先改为-90deg,效果以下:

再来个180度翻转的:

以及360度绕轴一圈的(先打住,没意思了啊,猜都猜出效果了),这里呢,关于透视原点perspective-origin由于没作定义,因此旋转的中规中举,我随便改一下,把父容器的透视原点属性值改为perspective-origin: right bottom,也就是右下角,获得的效果是下面这样的:

绕完X轴的看过一遍以后,绕Y轴的闭着眼就能想象。随便来一个吧,如今我把绕Y轴的角度定义成120度

@keyframes cubic{
0% {transform: rotateY(0)}
100% {transform: rotateY(120deg)}
}复制代码

有没有兴趣看看绕Z轴好比transform: rotateY(120deg)的效果:


其实想一想也是了,对于2D平面的图形,Z轴就是一个点,因此绕Z轴旋转就变成了普通的旋转动画效果。

仍是3D的玩起来更是花样百出。兴趣指数,五颗星!

3D动画一旦玩起来,是很可怕的,前面虽然各类属性设置来过一遍,但说到底,咱们用的SVG底图仍是2D的,一张平面的图转来绕去的能有什么意思?总归是缺少3D应有的使用场景。运用在多面体上的方法和效果下次再更。