CSS3景深、三维变换属性及旋转三维立方体的实现

ceco123 2年前
   <p>三维立体效果我觉得是CSS3中最有意思的地方,不得不佩服那些开发者大神们,让我们能够通过几行CSS代码就能得到酷炫的视觉体验。</p>    <h2>浏览器坐标系</h2>    <p>在讲正式语法之前,首先需要了解浏览器坐标系,这需要我们把浏览器界面想象成一个立体的场景。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4785ab4ee3f1e938fa3652106c7890e3.png"></p>    <p>这是网上流传很广的浏览器坐标系图片,从左到右的方向是浏览器x轴的正方向,从上到下的方向是浏览器y轴的正方向,而z轴正方向是面对于我们的,了解这个很重要,因为下面我们旋转元素需要借助它来理解。</p>    <h2>3D旋转</h2>    <p>我们在平面中使用的旋转只是单纯的让元素在平面旋转一定角度,在三维旋转中稍微要复杂一些,属性当然还是用我们的transform,三维旋转有下面三个函数分别对应三个维度的旋转:</p>    <ul>     <li>rotateX(xxdeg)</li>     <li>rotateY(xxdeg)</li>     <li>rotateZ(xxdeg)</li>    </ul>    <p>rotateX是让元素绕着x轴旋转,角度越大,元素绕着x轴顺时针旋转,类似于我们的单杠运动。</p>    <pre>  <code class="language-css">transform: rotateX(45deg);</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ceb1e2f492126d7106270efb98656167.jpg"></p>    <p>rotateY是让元素绕着y轴旋转,角度越大,元素绕着y轴顺时针旋转,类似于钢管舞运动..</p>    <pre>  <code class="language-css">transform: rotateY(45deg);</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e73eed8a2652dc88c447b1d4ea1d2b50.jpg"></p>    <p>rotateZ是让元素绕着z轴旋转,角度越大,元素绕着z轴顺时针旋转,这就是我们在二维平面的旋转,类似于转盘</p>    <pre>  <code class="language-css">transform: rotateZ(45deg);</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4a18e8cedd98d3c6b233b07a7a094ecd.png"></p>    <p>其实3D旋转还有一个合成的函数是rotate3d(num,num,num,deg),用的不是很多,我就简单说一下,参数并不是我们想那样的3个角度值,而是三个数字一个角度值,前三个数字分别表示绕x、y、z轴旋转的矢量值,最后一个表示在空间的旋转角度,等价关系如下</p>    <p>rotate3d(1,0,0,xxdeg) <==> rotateX(xxdeg)</p>    <p>rotate3d(0,1,0,xxdeg) <==> rotateY(xxdeg)</p>    <p>rotate3d(0,0,1,xxdeg) <==> rotateZ(xxdeg)</p>    <h2>3D位移与3D缩放</h2>    <p>我们在2D中用到translateX()和translateY()在平面移动,3D中我们多了translateZ()允许我们沿着z轴平移,同样可以使用合成函数translate3d(x,y,z),注意前两个值可以使用百分比形式,但是沿z轴平移的值只能使用长度值。同理我们的3D缩放</p>    <p>scaleX(num)、scaleY(num)、scaleZ(num)、scale3d(num,num,num)</p>    <p>至于它们的用法下面再通过例子来说,(3D的倾斜属性是不存在的,换句话说,不存在skew3d函数)</p>    <h2>透视/景深属性perspective</h2>    <p>景深这个名词,维基百科是这样就解释的</p>    <p>景深(英语:Depth of field, DOF)景深是指相机对焦点前后相对清晰的成像范围。在光学中,尤其是录影或是摄影,是一个描述在空间中,可以清楚成像的距离范围。虽然透镜只能够将光聚 到某一固定的距离,远离此点则会逐渐模糊,但是在某一段特定的距离内,影像模糊的程度是肉眼无法察觉的,这段距离称之为景深。当焦点设在超焦距处时,景深 会从超焦距的一半延伸到无限远,对一个固定的光圈值来说,这是最大的景深。</p>    <p>(看到这里,我的手默默的离开了键盘,仰天长叹,心想,这到底要什么样的学历才能看得懂)</p>    <p>我们可以这样来理解,景深就是我们的肉眼距离显示器的距离,景深越大,元素离我们越远,效果就不好,在我们CSS3中,perspective用于激活一个3D空间,属性值就是景深大小(默认none无景深),有两种用法</p>    <pre>  <code class="language-css">.stage {      perspective: 500px;  }</code></pre>    <p>应用景深的元素称为“舞台元素”,舞台元素的所有后代元素都会受影响,(如果后代元素中也添加了perspective属性,效果会叠加而不是覆盖)</p>    <pre>  <code class="language-css"><div class="stage">      <div class="demo"></div>  </div></code></pre>    <pre>  <code class="language-css">.stage {      width: 200px;      height: 200px;      border: 1px solid black;      margin: 100px auto;  }  .stage .demo {      width: 200px;      height: 200px;      background-color: orangered;      transform: rotateX(45deg);  }</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/112a1db02ed8b5021d448fdabddc29c8.png"></p>    <p>在这个例子中,我们把内部元素绕x轴旋转了45°后,由于他只是在二次元旋转,所以我们根本看不出来它旋转,但是我们现在加个景深</p>    <pre>  <code class="language-css">.stage {      width: 200px;      height: 200px;      border: 1px solid black;      margin: 100px auto;      perspective: 500px; /*增*/  }  .stage .demo {      width: 200px;      height: 200px;      background-color: orangered;      transform: rotateX(45deg);  }</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f3032d8d6b8af3dfb59cd3cdd95e512e.png"></p>    <p>这就相当于我们在舞台元素的中心位置往里看,这个子元素距离我们肉眼有500px,由于子元素的顺时针旋转,元素上半部分离我们远,所以看起来很小,元素下半部分离我们近,所以看起来稍大,这样就会产生很强的立体感</p>    <p>刚才我说道我们的肉眼相当于在舞台元素中心的位置,其实这个“眼睛”的位置是可以调整的,这用到了perspective-origin属性,默认的属性值就是 50% 50%,也就是舞台元素的中心位置,我们可以尝试调整视角。</p>    <pre>  <code class="language-css">.stage {      width: 200px;      height: 200px;      border: 1px solid black;      margin: 100px auto;      perspective: 500px;      perspective-origin: 10px 10px; /*增*/  }  .stage .demo {      width: 200px;      height: 200px;      background-color: orangered;      transform: rotateX(45deg);  }</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/a32ac3ff8fa0a0c1a970c1228ecd9f68.png"></p>    <p>这就相当于在舞台元素的距离原点(左上)10px,10px的位置往里看,理解这个需要我们一定的空间立体感</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f08ac0375878002704d4d9d31b8ede1e.png"></p>    <p>注意:景深大小一定要比你的动画元素大(我们不可能看到眼睛后面的东西)</p>    <p>景深的另一种用法,是应用在动画元素(不是舞台元素)变形的函数中,和其他变形函数写在一起</p>    <pre>  <code class="language-css">.stage .demo {      ......      transform: rotateX(45deg) perspective(100px);  }</code></pre>    <h2>3D属性transform-style</h2>    <p>这个属性指定了子元素如何在空间中展示,只有两个属性值:flat(默认)和preserve-3d,flat 表示所有子元素在2D平面呈现,preserve-3d 表示所有子元素在3D平面呈现,(prederve是保护、维持的意思,preserve-3d就是保持三维空间的意思),当然如果我们想要3D的效果,就要使用 transform-style: preserve-3d;</p>    <p>这个属性只是针对设置属性元素的子元素如何展示,而对子元素的子元素无效,而且对于设置了 overflow: hidden; 的元素,设置3D效果会失效,道理很简单,跳出了父元素平面的子元素无法显示了,结果自然还是2D效果,应用于这个属性的元素我们称作“容器”,这个属性我们下面通过一个例子再来体会</p>    <h2>背面可见属性backface-visibility</h2>    <p>通过这个元素我们可以指定当元素背对我们时是否可见,只有两个属性值visibility(默认)和hidden,如果我们希望元素背对我们不可见,就这样设置</p>    <pre>  <code class="language-css">.demo {      ...      backface-visibility: hidden;  }</code></pre>    <p>下面我通过一个例子来把上面讲到的属性全部实践一下</p>    <h2>示例:旋转的三维立方体</h2>    <pre>  <code class="language-css"><div class="stage">  <!--舞台元素,视角所在-->      <ul class="three-d-box">   <!--动画容器,通过它来控制整个立方体-->          <li>:capricorn:</li>  <!--动画元素,立方体的六个面-->          <li>:virgo:</li>          <li>:leo:</li>          <li>:cancer:</li>          <li>:libra:</li>          <li>:pisces:</li>      </ul>  </div></code></pre>    <pre>  <code class="language-css">ul {  /*调整ul标签的样式,取消内边距、外边距,和“点”样式*/      padding: 0;      margin: 0;      list-style-type: none;  }  .stage {  /*设置舞台元素在屏幕居中,设置合适的景深大小*/      position: relative;      width: 800px;      height: 800px;      margin: 100px auto;      perspective: 800px;  }  @keyframes move { /*设置动画关键帧*/      0% {          transform: rotateX(0deg);      }      25% {          transform: rotateX(180deg);      }      50% {          transform: rotateX(360deg) rotateY(0deg);      }      75% {          transform: rotateX(360deg) rotateY(180deg);      }             100% {          transform: rotateX(360deg) rotateY(360deg);      }  }  .stage .three-d-box {  /*动画容器居中在舞台元素中间*/      width: 200px;      height: 200px;      position: absolute;      left: 50%;      top: 50%;      margin: -100px 0 0 -100px;      transform-style: preserve-3d; /*设置3D属性让子元素三维空间呈现*/      animation: move 3s linear infinite; /*设置动画*/    }  .stage .three-d-box>li { /*设置动画子元素公共属性*/      position: absolute;      width: 200px;      height: 200px;      left: 0;      top: 0;      font-size: 50px;      line-height: 200px;      text-align: center;      opacity: 0.5;  }  /*为了保证我们对立方体位置的控制,我们需要让动画容器在立方体的中间位置*/  .stage .three-d-box>li:nth-child(1) {      background-color: red;      transform: translateZ(-100px);  }  .stage .three-d-box>li:nth-child(2) {      background-color: greenyellow;      transform: translateZ(100px);  }  .stage .three-d-box>li:nth-child(3) {      background-color: cornflowerblue;      transform: rotateX(90deg) translateZ(100px);  }  .stage .three-d-box>li:nth-child(4) {      background-color: orangered;      transform: rotateX(-90deg) translateZ(100px);  }  .stage .three-d-box>li:nth-child(5) {      background-color: deeppink;      transform: rotateY(90deg) translateZ(100px);  }  .stage .three-d-box>li:nth-child(6) {      background-color: lightcoral;      transform: rotateY(-90deg) translateZ(100px);  }</code></pre>    <p>大功告成</p>    <p>这样我们就会得到如下酷炫的三维立方体</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/47c9f258d890b051bef1a2f3c54af170.gif"></p>    <p>注意在3D变换transform中,旋转与位移函数的顺序不同,元素展现的位置是不同的,这是因为元素的坐标轴是随着我们变换而变化的。</p>    <p>上面的代码如果有不明白的地方,可以拷贝到浏览器进行调试,整体的思路就是</p>    <ol>     <li>设置舞台元素(perspective:xxxpx)</li>     <li>设置动画容器(transform-style:preserve-3d)</li>     <li>通过旋转、位移调整动画子元素的位置</li>     <li>对动画容器应用动画效果</li>    </ol>    <p>最后我们通过这个正方体来加深三维变换相关属性的理解</p>    <p>backface-visibility</p>    <p>添加样式前的正方体</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/31fdde7c78c9dba5a99dbdab7dfef66e.png"></p>    <p>现在我们来添加样式</p>    <pre>  <code class="language-css">.stage .three-d-box>li {      ......      backface-visibility: hidden;  }</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2af9eb76712f81d805be92f36f46e78f.png"></p>    <p>大家来找茬,可以看到背对我们的元素全部看不见了,这就是 backface-visibility: hidden; 的作用</p>    <p> </p>    <p>来自:http://www.webhek.com/css-3d-rotate-cube</p>    <p> </p>