本文转载于@oxxo的玩转CSS 3D系列教程第一篇:http://www.oxxostudio.tw/articles/201506/css-3d.html
這篇 CSS 3D 的文章,其实酝酿已久,从CSS 3D 出来的时候就已经在关注,只是要写 CSS 3D 真的很费工,里面有太多东西要讲,加上最近在做 Webduino 可以改变世界的事业 ( Webduino 超赞呀! ),所以就一直搁着了,趁着端午放假,一口气把它搞定吧!
虽然 CSS 3D 并非真的 3D,CSS 3D 坦白说就是纯粹利用计算的方法,借着浏览器的高效性能,在 2D 的空間绘制一个 3D 的图形,就像我们拿张约,用铅笔在上头画个正立方体之类的,也因为是借了浏览器的运算,自然而然非常地耗性能,往往只要有过多的形状转换为 3D 呈现,就会发现电脑的风扇开始狂转,这也是使用 CSS 3D 必须要注意的地方,毕竟 CSS 原本就不是拿来做 3D 应用的技术,可以画 3D,只是可以加强 CSS 呈现的美感和能力,但用在精细的 3D 动画或转场效果,还是交给专业的 3D 绘图软件来运行。
从这篇开始以及再来的一两篇,将会深入介绍 CSS 3D 的绘图以及直接做些应用,如果你已经会了 CSS 3D,不妨也可以看看正多面体该如何制作,可以参考這两篇:玩转 CSS 3D - 正四面体与正六面体、玩转 CSS 3D - 正八面体与正十二面体。
3D手式
我们这边先来用 Google SketchUp 这个免费的 3D 建模软件,看一下最普通的 3D 绘图的介面,里头最基本的会有三个元素,第一个:摄影镜头,第二个:立体空间,第三个:立体物件。
摄影镜头主要定义了观看者的角度,就如同我们在拍照,使用长焦距的望远镜头,物体可以拉近且不会变形,使用短焦距的广角镜,拍摄的物体就容易变形,从下图可以看出,镜头的焦距可以让空间內的物体产生不同的变形,至于立体空间则是具备了 X
、Y
、Z
三个座标轴的空间,立体物件则是在这个空间里头的物件。
所以绘制 CSS 的 3D 图形,最重要的也就是要架设这三个物件,不过因为在 CSS 里並沒有摄影镜头、立体空間...等。這些 3D 软件才有的元素,所以变成都是用 div
取代,在对应的 div
上头加入对应的 style 属性,就可以进行模拟,运用上面所提到的三个元素,我们这里就必须要用到三层div
,最外层是摄影镜头,第二层为立体空间,第三层是是立体空间內的立体元素,写出來的 HTML 长得就像下面这样:
<div class="camera">
<div class="space">
<div class="box"></div>
</div>
</div>
设定 camera
接着就要来把最外层的 div
( 以下通称 camera ) 设定为摄影镜头,设定的方法为添加 perspective-origin
以及 perspective
这两个属性,这个属性是什么呢?简单来说就是透视点以及镜头到透视点的距离,如果直接查询 perspective
,看到的八九不离十是下面这些图案:
然而在 W3C 里头对于 perspective
的解释则是下图这样,透视点同样也是物体到摄影机的距离 ( d
) ,但又因为 CSS 的 3D 空间里头具有 Z
轴,所以 perspective
的距离会因为 Z
轴的关系而有所缩放 ( 不过千万要注意,这里的 Z
指的是物体的 Z
轴,也就是 translateZ
,不是摄影机的 )。
此外,perspective-origin
是摄影机的中心点位置,预设相对应空间 div
( 以下都称为 space ) 的中心点,不做设定的话,预设都是 center center
( 或 50% 50%
),换句话说,作为摄影镜头的 camera 的三個维度,perspective-origin
代表了 X
和 Y
轴,而 perspective
代表 Z
轴 ( 和內容物体的 Z
轴相减才会变成摄影机的 ),camera 就可以在三维空间里头进行移动,下图同样是 W3C 对于 perspective-origin
所作的解释,当摄影镜头往上,图形的下半部就看不到了。
回到 CSS 来看的话,我们可以像下面這样设定,这时候画面完全不是正常的,因为还沒有设定空间和物体。
.camera{
width:200px;
height:200px;
perspective-origin:center center;
perspective:500px;
}
设定 space
摄影机完成后,就是要设定一个立体空间 space,这个空间设定的方式很简单,只要设定一个属性:transform-style
,这个属性预设为 flat
,也就是只要是這个 div
內的子元素,一律都是以扁平 ( flat
) 的方式呈现,所属的变换 transform
也一律都是用 flat
的方式变换,换句话说就是沒有 Z
轴的存在,为了让內容元素都是立体元素,所以我们要將 transform-style
设为 3D
,如此一来內容元素就全部都可以用 3D 进行变换,为了方便区分,下面我将 space 外围多加一个 boder
做区别。
.space{
width:100%;
height:100%;
border:1px dashed #000;
transform-style:3d;
}
设定 box
最后就是內容元素 box 了,我们可以添加一个 100px x 100px
的 box 进去,接着,用这个 box 来复习一下前面讲的观念,在沒有设定 box 的 traslateZ
、rotate
的情形下,不论我们如何去修改 camera 的 perspective-origin
和 perspective
,box 的大小和位置都不会有变化,为什么呢?因为在沒有设定 box 的 translateZ
或 rotate
,让 Z
的深度有所变化,摄影机透过 perspective
看出去的位置都是相同的,也造成不论怎么去看这个 box 都是一样的大小。
.box{ width:100px; height:100px; background:#069; transform:translateX(50px) translateY(50px); }
不过当我们给 box 改变 Z
轴的深度之后 ( 这里我先把 translateZ
设定为 150px
),再去改变 camera 的 perspective-origin
和 perspective
,一切彷佛就有了变化。
.box{
width:100px;
height:100px;
background:#069;
transform:translateX(50px) translateY(50px) translateZ(150px);
translateZ(150px);
translateZ(150px);
}
大概了解之后,来把 box 旋转一下角度,看得应该就会更清楚,当摄影机变成广角,也就是 perspective
变短,整个旋转后变形也会更加明显,大家可以用开发者工具修改 camera 的 perspective
就会明白。
.box{
width:100px;
height:100px;
background:#069;
transform:translateX(50px) translateY(50px) rotateY(60deg);
}
改变一下 perspective-origin
也会很有意思。
我们加入多一点的 box,并且让这些 box 的位置改变或旋转,看看效果如何,这里比较需要注意的地方,是我们必须要额外在每个 box 加入 position:absolute
的属性,因为 div
本身为 block 属性,会互相挤压,要设定位置为绝对位置,才会正确地放在 space 里头。
.space div{
position:absolute;
width:100px;
height:100px;
}
.box1{
background:#069;
transform:translateX(50px) translateY(50px) rotateY(60deg);
}
.box2{
background:#c00;
transform:translateX(100px) translateY(20px) rotateX(60deg);
}
.box3{
background:#f90;
transform:translateX(0px) translateZ(-250px) rotateY(20deg);
}
.box4{
background:#0c9;
transform:translateX(20px) translateY(80px) rotateX(-80deg);
}
正如上述的三个 3D 元素,我们就可以轻松的绘制 CSS 3D 图形,不过除了 camera、space 和 box 之外,还有一个最重要最重要最重要的撰写規律在里头 ( 因为很重要所以要说三次 ),这个規律就是 tramsform
里头是有順序的,因为 CSS 3D 完全是由 2D 演算而来,并不是真的像 3D 软件是真的有 3D 的空间,所以就变成会「按照順序」进行演算,而且又因为 transform
会造成物体的整个座标轴变换,在順序的编排上就格外重要。
例如今天我先让 box 在 X
轴上水平位移 100px
再绕着 Y
轴順时针转 60
度,和先绕 Y
轴順时针转 60
度,再在 X
轴上头水平位移 100px
的结果会完全不同,因为当我先绕了 Y
轴转动,整个 X
轴也会跟著转动,这时候再做水平位移,位置就会像是在深度做变换。
.space div{
position:absolute;
width:100px;
height:100px;
}
.box1{
background:#069;
transform:translateY(50px) translateX(100px) rotateY(60deg);
}
.box2{
background:#c00;
transform:translateY(50px) rotateY(60deg) translateX(100px);
}
transform
的数量少还比较看不出來,当今天 transform
里头数量一多,造成的差异就更加明显,这也是在玩 CSS 3D 最最最最最需要注意的重点所在,一定要注意,一定要注意,一定要注意,非常重要所以再说三次呀!
.space div{
position:absolute;
width:100px;
height:100px;
}
.box1{
background:#069;
transform:translateY(50px) translateX(100px) rotateY(60deg) rotateX(60deg) translateX(-50px);
}
.box2{
background:#c00;
transform:translateX(-50px) translateY(50px) rotateX(60deg) rotateY(60deg) translateX(100px);
}
以上就是 CSS 3D 的原理解析,坦白说如果明白了 3D 的结构组成,CSS 的 3D 就沒有难度,总而言之,就是先建立好三個元素:摄影机、立体空间、立体物件,就可以开始玩转 CSS 3D 啰!
本文转载于@oxxo的玩转CSS 3D系列教程第一篇:http://www.oxxostudio.tw/articles/201506/css-3d.html