前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「CSS 3D 专题」搞懂 CSS 3D,你必须理解 perspective(视域)这个属性

「CSS 3D 专题」搞懂 CSS 3D,你必须理解 perspective(视域)这个属性

作者头像
前端达人
发布2019-08-13 11:58:04
2K0
发布2019-08-13 11:58:04
举报
文章被收录于专栏:前端达人前端达人
关注前端达人,与你共同进步

开篇

上一章节《学习前,你需要了解什么是CSS 3D?》里,我们一起了解什么是CSS 3D,本篇章节笔者将带着大家学习 perspective(视域)这个重要属性,在我们接触 CSS 3D 时,大多数开发人员都使用过,但是深入理解其原理的不知有多少。

首先强调下,理解这个属性至关重要,这个 perspective(视域)属性通常作用在外部容器元素上,例如body,figure和 div 等标签上。这样我们就在3D空间操作内在的子元素。你可以将这个属性理解为类似flexbox这个属性,因为其也可以影响内部元素的外观和位置。如果没有这个属性,即使我们应用了 CSS 3D 的Transforms属性我们也无法看到预期的3D视觉效果。

01

perspective(视域)原理

其实计算机的3D场景就是对现实世界的模拟,在了解这个属性前,我们先设想一下这个场景:随着爱好摄影的人越来越多,我们会经常拿着自己心爱的相机去拍照。拍照最重要莫过于这三前提要素:

第一个:镜头,第二个:拍摄的环境的空间,第三个:要拍摄的物件。

相机镜头主要定义了观看者的角度,使用长焦距的望远镜头,物体可以拉近且比较不会变形,使用短焦距的广角镜,拍摄的物体就容易变形,从下图可以看出,镜头的焦距可以让空间内的物体产生不同的变形。如下图所示:

所以在CSS 3D的世界里,最重要的也就是要找到并创建这三个物件要素,不过因为在CSS世界里并没有摄影镜头、拍摄的环境的空间等这些真实世界拍摄需要的要素,所以变成都用div进行展现,在对应的div 上头加入对应的style属性,就可以进行模拟,藉由上面所提到的三个要素,我们这里就必须要用到三层div,最外层是摄影镜头,第二层为立体空间,第三层则是立体空间内的立体元素,写出来的 HTML 长得就像下面这样:

代码语言:javascript
复制
<div class = “camera” >
    < div class = “space” >
        < div class = “box” > </ div >
    </ div >
</ div>

02

设定camera

如上述代码我们将最外层的div(以下通称camera )定义为相机镜头,为了让其具有相机的拍摄功能,我们就要为其定义相关的属性,camera包含两个属性:perspective-origin 和 perspective。

这两个属性到底是啥呢?简单的来说就是透视点以及镜头到透视点的距离,如果你想了解的更清楚些,你也许和我一样在网络上进行查询,八九不离十你会看到如下所示的图(来源:http://mathworld.wolfram.com/Perspective.html,佛罗伦萨建筑师 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 来看的话,我们可以像下面这样设定,这时候会完全没有画面是正常的,因为还没有设定空间和物体。

代码语言:javascript
复制
.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;
}

关于视域值的设定请参照下表:

请注意,上面的值是近似值:精确整数和度量单位取决于许多因素,包括容器和子元素的相对大小。

03

设定space

摄影机完成后,我们需要定义一个立体空间space,这个空间设定的方式很简单,只要设定一个属性:transform-style,这个属性默认值为flat,也就是只要是这个div内的子元素,一律都是以扁平( flat )的方式呈现,所属的变换transform也默认一律都是用flat的方式变换,换句话说就是没有Z轴的存在,为了让内容元素都是立体元素,所以我们要将transform-style的值设为3d属性,如此一来内容元素就全部都可以用3D进行变换,为了方便区分,下面我将会设置space的boder属性设置为黑色虚线用于识别。

代码语言:javascript
复制
.space{
    width:100%;
    height:100%;
    border:1px dashed #000;
    transform-style:3d;
    -moz-transform-style:3d;
    -webkit-transform-style:3d;
}

上述代码的效果如下图:

04

设定box

最后就是内容元素box了,我们可以添加一个100px x 100px的box,接下来,我们先用这个box来验证一下前面讲的观点,在没有设定box的traslateZ、rotate的情形下,不论我们如何去修改camera的perspective-origin和perspective的值,box的大小和位置都不会有变化,为什么呢?因为在没有设定的box的translateZ或rotate,让Z的深度有所变化,摄影机透过perspective看上去的位置都是相同的,也造成不论怎么去看这个box都是一样的大小。示例代码如下:

代码语言:javascript
复制
.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,终于能看到有效果变化了。

代码语言:javascript
复制
.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就会明白。

代码语言:javascript
复制
.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 也会很有趣味:

05

添加更多的box

你可能要变换多个物体,接下来我们尝试下添加多个box。并且让这些box的位置改变或旋转,看看效果如何,这里比较需要注意的是我们必须要在最外层的div加入position:absolute的属性,因为div本身为block属性,会互相挤压,要设定位置为绝对位置,才会正确地放在space空间里。

示例代码如下:

代码语言:javascript
复制
.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轴也会跟着转动,这时候再做水平位移,位置就会像是在深度做变换。示例代码如下:

代码语言:javascript
复制
.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最最最最最需要注意的重点所在,一定要注意,一定要注意,一定要注意,非常重要所以再讲三次呀!示例代码如下:

代码语言:javascript
复制
.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);
}

06

小实验——帅哥看过来

上一章节,我们完成了我们的第一个例子美女看过来,在本章节的结束前,看本文的妹子有福了,你可以亲自体调控视角来看帅哥,呵呵。

示例效果如下:

由于本章节篇幅有限,就不在这里贴大量的代码了,感兴趣的点击体验地址(请在PC端用chrome进行体验):https://www.qianduandaren.com/demo/css3d/02/,查看源码。

本章节就到这里,今天我们一起深刻理解了perspective(视域)这个重要属性,并一起完成了几个例子,加深了对这个属性的理解,只有理解这个属性后,我们才能更进一步的学习CSS 3D,今天的内容有些多,需要你慢慢消化。最后重要的事情说三遍,理解perspective(视域)很重要!理解perspective(视域)很重要!理解perspective(视域)很重要!

因为很重要,下一章节我们要继续学习使用perspective(视域)的有哪些坑和注意事项。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档