详解CSS3 3D的perspective属性
perspective 属性对于 3D 变形来说至关重要。该属性会设置查看者的位置,并将可视内容映射到一个视锥上,继而投到一个 2D 视平面上。如果不指定透视,则 Z 轴空间中的所有点将平铺到同一个 2D 视平面中,并且变换结果中将不存在景深概念。
上面的描述可能让人难以理解一些,其实对于 perspective 属性,我们可以简单的理解为视距,用来设置用户和元素 3D 空间 Z 平面之间的距离。而其效应由他的值来决定,值越小,用户与 3D 空间 Z 平面距离越近,视觉效果更令人印象深刻;反之,值越大,用户与 3D 空间 Z 平面距离越远,视觉效果就很小。
使用范围
这个 perspective(视域)属性通常作用在外部容器元素上,例如 body,figure 和 div 等标签上。这样我们就在 3D 空间操作内在的子元素。你可以将这个属性理解为类似 flexbox 这个属性,因为其也可以影响内部元素的外观和位置。如果没有这个属性,即使我们应用了 CSS 3D 的 Transforms 属性我们也无法看到预期的 3D 视觉效果。
perspective(视域)原理
其实计算机的 3D 场景就是对现实世界的模拟,在了解这个属性前,我们先设想一下这个场景:随着爱好摄影的人越来越多,我们会经常拿着自己心爱的相机去拍照。拍照最重要莫过于这三前提要素:
第一个:镜头,
第二个:拍摄的环境的空间,
第三个:要拍摄的物件。
相机镜头主要定义了观看者的角度,使用长焦距的望远镜头,物体可以拉近且比较不会变形,使用短焦距的广角镜,拍摄的物体就容易变形,从下图可以看出,镜头的焦距可以让空间内的物体产生不同的变形。如下图所示:
所以在 CSS 3D 的世界里,最重要的也就是要找到并创建这三个物件要素,不过因为在 CSS 世界里并没有摄影镜头、拍摄的环境的空间等这些真实世界拍摄需要的要素,所以变成都用 div 进行展现,在对应的 div 上头加入对应的 style 属性,就可以进行模拟,藉由上面所提到的三个要素,我们这里就必须要用到三层 div,最外层是摄影镜头,第二层为立体空间,第三层则是立体空间内的立体元素,写出来的 HTML 长得就像下面这样:
<div class = “camera” > < div class = “space” > < div class = “box” > </ div > </ div > </div>
设定 camera
如上述代码我们将最外层的 div(以下通称 camera)定义为相机镜头,为了让其具有相机的拍摄功能,我们就要为其定义相关的属性,camera 包含两个属性:perspective-origin 和 perspective。
这两个属性到底是啥呢?简单的来说就是透视点以及镜头到透视点的距离,如果你想了解的更清楚些,你也许和我一样在网络上进行查询,八九不离十你会看到如下所示的图(佛罗伦萨建筑师 Florentine architect(1377-1446)阐述的透视图的原理):
这张图我也不解释太多,有点太理论,主要讲述了透视的原理规则,感兴趣的可以去链接进行查看。
然而在 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 代码,我们可以像下面这样进行定义,这时候我们还无法体验 3D 效果,这是正常的,我们这里只是告诉了计算机摄像机在哪,还没定义拍摄环境的空间。
回到 CSS 来看的话,我们可以像下面这样设定,这时候会完全没有画面是正常的,因为还没有设定空间和物体。
.camera{ width:200px; height:200px; perspective-origin:center center; -moz-perspective-origin:center center; -webkit-perspective-origin:center center; perspective:500px; -moz-perspective:500px; -webkit-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; -moz-transform-style:3d; -webkit-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); -moz-transform:translateX(50px) translateY(50px); -webkit-transform:translateX(50px) translateY(50px); }
无论你怎么修改 camera 的 perspective 属性,效果都是一致的,效果如下图:
不过当我们给 box 改变 Z 轴的深度之后(这里我先把 translateZ 设定为 150px ),再去改变 camera 的 perspective-origin 和 perspective,终于能看到有效果变化了。
.box{ width:100px; height:100px; background:#069; transform:translateX(50px) translateY(50px) translateZ(150px); -moz-transform:translateX(50px) translateY(50px) translateZ(150px); -webkit-transform:translateX(50px) translateY(50px) translateZ(150px); }
大概了解之后,让我们把 box 旋转一下角度,看得应该就会更清楚,当摄影机的变成广角,也就是 perspective 变短,整个旋转后变形的效果也会更加明显,大家可以用谷歌浏览器的开发者工具修改 camera 的 perspective 就会明白。
.box{ width:100px; height:100px; background:#069; transform:translateX(50px) translateY(50px) rotateY(60deg); -moz-transform:translateX(50px) translateY(50px) rotateY(60deg); -webkit-transform:translateX(50px) translateY(50px) rotateY(60deg); }
改变一下 perspective-origin 也会很有趣味:
添加更多的 box
你可能要变换多个物体,接下来我们尝试下添加多个 box。并且让这些 box 的位置改变或旋转,看看效果如何,这里比较需要注意的是我们必须要在最外层的 div 加入 position:absolute 的属性,因为 div 本身为 block 属性,会互相挤压,要设定位置为绝对位置,才会正确地放在 space 空间里。
示例代码如下:
.space div{ position:absolute; width:100px; height:100px; } .box1{ background:#069; transform:translateX(50px) translateY(50px) rotateY(60deg); -moz-transform:translateX(50px) translateY(50px) rotateY(60deg); -webkit-transform:translateX(50px) translateY(50px) rotateY(60deg); } .box2{ background:#c00; transform:translateX(100px) translateY(20px) rotateX(60deg); -moz-transform:translateX(100px) translateY(20px) rotateX(60deg); -webkit-transform:translateX(100px) translateY(20px) rotateX(60deg); } .box3{ background:#f90; transform:translateX(0px) translateZ(-250px) rotateY(20deg); -moz-transform:translateX(0px) translateZ(-250px) rotateY(20deg); -webkit-transform:translateX(0px) translateZ(-250px) rotateY(20deg); } .box4{ background:#0c9; transform:translateX(20px) translateY(80px) rotateX(-80deg); -moz-transform:translateX(20px) translateY(80px) rotateX(-80deg); -webkit-transform:translateX(20px) translateY(80px) rotateX(-80deg); }
如上图所示,上述的三个 3D 元素,就这样被我们展现在了 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); -moz-transform:translateY(50px) translateX(100px) rotateY(60deg); -webkit-transform:translateY(50px) translateX(100px) rotateY(60deg); } .box2{ background:#c00; transform:translateY(50px) rotateY(60deg) translateX(100px); -moz-transform:translateY(50px) rotateY(60deg) translateX(100px); -webkit-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); -moz-transform:translateY(50px) translateX(100px) rotateY(60deg) rotateX(60deg) translateX(-50px); -webkit-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); -moz-transform:translateX(-50px) translateY(50px) rotateX(60deg) rotateY(60deg) translateX(100px); -webkit-transform:translateX(-50px) translateY(50px) rotateX(60deg) rotateY(60deg) translateX(100px); }
结束语
以上就是今天小编带大家一起深刻理解了 perspective(视域)这个重要属性,并一起完成了几个例子,加深了对这个属性的理解,只有理解这个属性后,我们才能更进一步的学习 CSS 3D,今天的内容有些多,需要你慢慢消化。
码云笔记 » 详解CSS3 3D的perspective属性