前言
在当前大部分的网站里,基本上页面效果都限制在二维平面空间里,最常见的是一些使用阴影和平移转换的二维动画,很少看到一些CSS 3D转换的效果。在之前,可能因为浏览器兼容性问题或者设备硬件性能,我们不考虑在页面中引入3D转换效果,但如今,CSS 3D转换属性在现代浏览器上得到了普遍支持,硬件设备的性能也得到飞跃式提升,我们可以去尝试在页面中使用3D转换效果了,不得不说这是一件非常酷的事。
本文中会有一些3D转换的概念和示例,来帮助你尝试和理解3D转换,让你对3D转换有一个入门理解。在现实场景中,是否需要将3D转换应用在工作中,还需要你自己来判断它对你的工作是有益的还是一种负担。不过不管如何,学习一下3D转换的知识总没有错的,万一哪天用到了呢。
好了,下面我们就开始进行CSS 3D转换的旅程~
1. 转换
首先我们来了解一下转换的概念。转换包含了3个基本操作——平移、旋转和缩放,它们会来控制转换对象如何放置以及放置的方向是什么。所有的转换会围绕3个轴进行,也就是坐标系中的x轴、y轴和z轴:
- X轴,水平方向从左往右,值变大
- Y轴,垂直方向从下往上,值变大
- Z轴,垂直于屏幕方向,值越大,说明越靠近用户
接下来我们进行讨论的变换都是在这3个轴上进行的,下面是3个轴的一个空间示意图:
所有的转换一共有三种。首先我们看一下平移或移动,它是沿着一个轴或者多个轴进行位置的移动,我们使用translateX
、translateY
、translateZ
或者translate3d
这些CSS属性来控制对象在三维空间中的移动。
我们通过下面的代码片段来看一下对象的平移在不同轴上是怎样的效果:
这个代码中的动画分别演示了X轴、Y轴、Z轴3个方向上的平移运动效果。想要在Z轴方向上出现动画演示效果,其中一个css属性至关重要:perspective: 10em;
。这个属性会在下文中具体说明。
虽然我们在演示过程中使用了translateX
、translateY
、translateZ
,但是为了方便我们在多个轴上进行平移,CSS提供了缩写属性translate3d
,下面的写法是等价的:
.translated {
transform:
translateX(20px) /* x轴向右平移20px */
translateY(-20px) /* y轴向下平移20px */
translateZ(20px); /* z轴向更靠近用户的方向平移20px */
}
.translated-shorthand {
transform: translate3d(20px, -20px, 20px);
}
接下来,我们再通过一段代码演示,展示一下3维空间里,对象是如何进行旋转变换的:
我们可以看到,绕着Z轴旋转和2D下的旋转效果是一样的,但是绕X轴和绕Y轴旋转的效果则完全不一样。和translate3d
一样,旋转也有一个缩写rotate3d
来表示一个轴或多个轴的旋转运动:
.rotated {
transform:
rotateX(20deg) /* X轴方向旋转20deg */
rotateY(-20deg) /* Y轴方向旋转-20deg" */
rotateZ(20deg); /* Z轴方向旋转20deg */
}
.rotated-shorthand {
transform: rotate3d(20deg, -20deg, 20deg);
}
最后我们再来看第三种也是最后一种变换——缩放(scale
)。在CSS中,缩放只是使用scaleX、scaleY、scaleZ或简写scale3d单纯的调整对象大小,由于我们的演示对象是二维的,所以在Z轴上的缩放没有任何意义,而在X轴、Y轴上的缩放等同于改变对象的宽度和高度。
我们也可以通过scale3d
属性简写scaleX
、scaleY
、 scaleZ
,来表示在一个轴或多个轴的旋转。
.scaled {
transform:
scaleX(0.5); /* X轴方向缩放 */
scaleY(1.5); /* Y轴方向缩放 */
scaleZ(0.5); /* Z轴方向缩放 */
}
.scaled-shorthand {
transform: scale3d(0.5, 1.5, 0.5);
}
2. 参考系
在上面的示例中,我们可以看到,所有的变换运动都是参考一定位置来进行操作的。换句话来说,参考系决定了一个对象是如何运动的。因此请记好,每个对象的参考框架是它在文档对象模型(DOM)中的父对象。下面我们用一个例子来演示一下:
<div class="square parent">
<div class="square child"></div>
</div>
假设我们将父元素向右平移20像素,并将子元素向上平移20像素。
.parent {
transform: translateX(20px);
}
.child {
transform: translateY(20px);
}
子元素的向上平移是相对于父元素的,这意味着子元素将向右平移20个像素,向上平移20个像素。
理解了参考系,我们就可以将不同3D运动对象组合起来,以此来实现更复杂的3D效果。
3. 透视(perspective)
在CSS中,3D效果的展示与透视属性密不可分,它代表着观察者和3D对象的距离,它的值影响着用户对3D效果的感知,较低的透视值会放大屏幕上的3D效果,而较高的透视值会减弱屏幕上的3D效果。下面我们通过代码演示来查看透视值对3D效果的影响:
在示例代码中,我们可以看到,perspective 透视值从左往右是10em、20em、100em依次增加,但是3D效果从左往右开始减弱。
perspective 除了上面那种方式可以设置值,我们还有第二种方式来设置,它通过perspective()
函数调用来设置,类似下面这样:
transform: perspective(200px) rotateX(20deg);
这里必须要强调的是,perspective()
的使用必须在rotateX()
或其它transform函数前面,而且虽然这两种设置方式都可以去激活对象的3D效果,但是它们也有一些不同处:
perspective
属性设置在需要3D效果的元素的父元素上面,而perspective()
函数设置在需要3D效果的元素自身上面。perspective
属性会保证激活3D空间的父元素里的子元素,都共用一个3D空间,而perspective()
函数设置在每一个元素上时都会激活一个3D空间,导致每个元素都会有自己的3D效果,排列效果不会如预期那样。
下面我们通过一个示例来展示perspective
属性和perspective()
函数的不同处:
我们除了设置透视距离,我们还可以通过perspective-origin
来设置透视点的位置,如果我们设置透视点在左边,那就好像用户是在左边对透视对象进行观察,如果设置透视点的位置再上侧,就好像用户从一个更高的角度来观察。
perspective-origin
属性设置了透视点在X轴和Y轴的位置,默认情况下为:perspective-origin: 50% 50%
。下面我们通过一个例子来展示不同perspective-origin
值对3D效果的影响:
最后一个和CSS 3D效果相关的属性是transform-style
,它也是css中3D的关键,默认值是flat,如果你要在元素上实现3D效果的话,就必须用上transform-style: preserve-3d,否则就只是平面的变换,而不是3D的变换。
进阶
上文我们已经较为详细的解释了3D变换效果中相关的知识,下面我们通过案例来进一步学习3D转换效果。
1. 翻转卡片
首先我们来实现一个3D翻转卡片的效果。我们定义一个卡片,有正面和反面,当鼠标hover上去的时候,卡片翻转到反面,离开时翻转到正面。我们先来看一下效果:
首先我们定义一个用来开启3D空间的场景,然后在其内定义一个卡片,卡片内部包含了两个二维对象,代表卡片的正面和反面:
<div class="scene">
<div class="card">
<div class="face front">正面</div>
<div class="face back">反面</div>
</div>
</div>
HTML结构写完之后,接着我们来写对应的CSS样式。
定义3D空间:
.scene {
width:10em;
height:15em;
perspective: 30em;
}
接下来写卡片的CSS样式。我们这里添加一个额外的属性transform-style,它用来控制子元素的呈现方式是在2D还是3D空间中呈现。使用值preserve-3d来确保卡片的两个面以3D方式呈现。
.card {
width:100%;
height:100%;
position:relative;
transition: transform 0.5s;
transform-style: preserve-3d;
}
当我们设置好卡片的样式之后,接下来就该设置卡片每一面的样式了。这里的重点是要设置每一面的背面隐藏不被渲染,如果不设置的话,我们会发现,背面会一直在正面的上面:
.face {
width:100%;
height:100%;
color:#FFF;
line-height:15em;
text-align:center;
position:absolute;
/* 每面的背面不被渲染出来 */
backface-visibility:hidden;
}
.front {
background-color:#0379ff;
}
.back {
background-color:#333;
transform: rotateY(180deg);
}
最后,我们再卡片加上一个hover之后绕Y轴旋转180度样式即可,这样,一个翻转卡片的3D效果就出来了。
.scene:hover .card {
transform: rotateY(180deg);
}
以上我们的效果都是依赖于转换和透视的概念来完成的,通过二维平面的转换和组合,我们可以完成更加复杂的3D效果。接下来我们来看一个立方体旋转的效果。
2. 旋转立方体
接下来我们就来实现一个最简单的几何体——立方体的旋转效果。
首先我们在HTML中定义立方体的3D场景、立方体对象以及立方体的6个面:
<div class="scene">
<div class="cube">
<div class="face front">front</div>
<div class="face right">right</div>
<div class="face left">left</div>
<div class="face back">back</div>
<div class="face top">top</div>
<div class="face bottom">bottom</div>
</div>
</div>
然后定义场景的CSS样式,开启3D效果:
.scene {
width:10em;
height:10em;
perspective:10em;
}
定义立方体的样式,开启立方体的3D转换:
.cube {
width:100%;
height:100%;
position:relative;
transform-style:preserve-3d;
}
定义立方体每一面的样式,添加一个背景色:
.face {
width:100%;
height:100%;
position:absolute;
background-color:rgba(3, 121, 255, 0.5);
color:#FFF;
line-height:10em;
text-align:center;
}
到目前为止,每个面都是堆叠在一起的,我们需要通过旋转、平移来将它们组装成一个立方体。前、后、左、右四个面沿着y轴旋转,上、下两面沿着x轴旋转。
.front { transform: rotateY(0deg) }
.right { transform: rotateY(90deg) }
.left { transform: rotateY(-90deg) }
.back { transform: rotateY(180deg) }
.top { transform: rotateX(90deg) }
.bottom { transform: rotateX(-90deg) }
这个时候,立方体的每面都是以原点为中心的,我们现在沿着z轴移动每个面,让每个面正好拼成一个立方体。由于立方体的长宽高为10em,所以每个面只用移动5em距离即可。
.front { transform: rotateY(0deg) translateZ(5em); }
.right { transform: rotateY(90deg) translateZ(5em); }
.left { transform: rotateY(-90deg) translateZ(5em); }
.back { transform: rotateY(180deg) translateZ(5em); }
.top { transform: rotateX(90deg) translateZ(5em); }
.bottom { transform: rotateX(-90deg) translateZ(5em); }
最后我们只要再给立方体添加一个旋转动画就大功告成了。
.cube {
width:100%;
height:100%;
position:relative;
+ animation: spinning 4s infinite;
transform-style:preserve-3d;
}
+@keyframes spinning {
+ from { transform: translateZ(-5em) rotateY(0deg); }
+ to { transform: translateZ(-5em) rotateY(360deg); }
+}
现在让我们来看一下代码运行之后的效果:
结语
在本文中,我们介绍了使用纯CSS进行3D变换的基础知识,包含3D转换、参考下、透视点等相关概念,最后我们通过翻转卡片和旋转立方体两个示例来进一步理解前面介绍的概念。这些内容只能说是一个入门的介绍,希望能在现实开发中帮助大家。
最后,文中如有错误,敬请指正!