css3 transform属性

本文详细介绍了如何利用CSS3的transform属性创建一个可手动旋转和平移的3D正方体。通过rotate和translate属性,结合3D变换,实现了正方形到正方体的转变,并通过添加平移属性展示了更复杂的3D效果。文章还讨论了坐标轴的变化以及如何通过外层元素独立控制旋转和平移,以实现更直观的平移操作。
摘要由CSDN通过智能技术生成

本文详细介绍tranform属性,通过逐步制作一个可转动正方体的例子介绍此属性

首先看下最终的效果:

1.用法格式

transform:字面解释即变形,对元素的图形进行转变,支持元素从2D向3D转换,即可展示3D的元素

transform的值有rotate(旋转)skew(扭曲)scale(缩放)translate(平移)matrix(矩阵变形)

本文介绍rotate(旋转)和translate(平移)

上述效果用此两个属性值即可完成,具体属性值介绍请移步MDN或W3School

2.关于图形元素从2D到3D的变换过程

我们平时使用css时,因为屏幕本身是一个平面,默认使用2D效果,我的理解是在一个只有x轴、y轴的平面上描绘图形,当使用3D效果时,可以新增操作一个Z轴,默认Z轴是垂直于屏幕,当我们使用transform的rotate控制图形时,可看到其3D效果。

3.制作旋转正方体

3.1一个旋转的正方形

先从一个简单图形开始,我们来考察下transform的rotate、translate效果,以下代码描绘一个渐变的正方形

<!DOCTYPE html>
<html lang="en">
<head>
  <title>3Dbox</title>
  <style>
    #space {
      /* background-color: black;  */
    }
    #box {
      width: 180px;
      height: 180px;
      background-image: linear-gradient(#e66, #36c);
      margin: 180px auto;
    }
  </style>
</head>
<body>
  <div id="space">
    <div id="box">
    </div>
  </div>
</body>
</html>

为了更好展示图片效果,每次截取图片都是整个屏幕

添加一行代码到box选择器

 transform: rotateX(45deg); /* 元素绕x轴正向旋转45度 */

查看效果:

(绝不是压缩!发挥下想象力)图片绕x轴旋转了45°,可看到上半部分往里收缩,下半部分向外翻转。

关于旋转的理解 :前文提到过3D图形建立了x轴、y轴、z轴,默认情况下,x轴与屏幕水平向右,y轴垂直于x轴并向下,z轴从屏幕延伸出来垂直于屏幕,基点(3轴交汇点)在图形的正中心,当图形绕x轴正方向旋转,可看作从x轴方向逆时针旋转,当图形绕x轴负方向旋转,可看作从x轴正方向顺时针旋转,其他旋转效果类似。轴的方向随着旋转而改变。

为了更好体现旋转效果,我们编写一个手动控制旋转正方形的代码,最终效果:

旋转正方形

首先编写html,在上面代码地基础上,添加旋转控制滚动条内容:

  <div class="option">
    <p>rotate x: <span id="rotatex-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatex" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate y: <span id="rotatey-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatey" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate z: <span id="rotatez-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatez" value="0" class="range-control"
      onmousemove="change()" /><br />
  </div>

对应的样式:

    .option {
      width: 700px;
      font-size: 16px;
      font-weight: bold;
      margin: 0 auto;
    }

    .range-control {
      width: 700px;
    }

新增change方法,方法的具体思路是首选获取input的value值,然后通过此值给box添加tranform属性并赋予相对应的rotate值,同时显示当前旋转值(即改变span里面的值):

    function change() {
      let rotatex = document.getElementById("rotatex").value;
      let rotatey = document.getElementById("rotatey").value;
      let rotatez = document.getElementById("rotatez").value;
      document.getElementById('box').style.transform = "rotateX("+rotatex+"deg) rotateY("+rotatey+"deg) rotateZ("+rotatez+"deg)";
      document.getElementById('rotatex-span').innerText = rotatex;
      document.getElementById('rotatey-span').innerText = rotatey;
      document.getElementById('rotatez-span').innerText = rotatez;
    }

整体代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>3Dbox</title>
  <style>
    #space {
 
    }

    #box {
      width: 180px;
      height: 180px;
      background-image: linear-gradient(#e66, #36c);
      margin: 180px auto;

    }

    .option {
      width: 700px;
      font-size: 16px;
      font-weight: bold;
      margin: 0 auto;
    }

    .range-control {
      width: 700px;
    }
  </style>
  <script>
    function change() {
      let rotatex = document.getElementById("rotatex").value;
      let rotatey = document.getElementById("rotatey").value;
      let rotatez = document.getElementById("rotatez").value;
      document.getElementById('box').style.transform = "rotateX("+rotatex+"deg) rotateY("+rotatey+"deg) rotateZ("+rotatez+"deg)";
      document.getElementById('rotatex-span').innerText = rotatex;
      document.getElementById('rotatey-span').innerText = rotatey;
      document.getElementById('rotatez-span').innerText = rotatez;
    }
  </script>
</head>

<body>
  <div id="space">
    <div id="box">
    </div>
  </div>
  <div class="option">
    <p>rotate x: <span id="rotatex-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatex" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate y: <span id="rotatey-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatey" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate z: <span id="rotatez-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatez" value="0" class="range-control"
      onmousemove="change()" /><br />
  </div>
</body>

</html>

3.2 展示平移属性

以上都是旋转属性,接下来再添加一些平移属性,按照上面代码思路,得到以下代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>3Dbox</title>
  <style>
    #space {}

    #box {
      width: 180px;
      height: 180px;
      background-image: linear-gradient(#e66, #36c);
      margin: 180px auto;
      transition: transform 1s linear;
    }

    .option {
      width: 700px;
      font-size: 16px;
      font-weight: bold;
      margin: 0 auto;
    }

    .range-control {
      width: 700px;
    }
  </style>
  <script>
    function change() {
      let rotatex = document.getElementById("rotatex").value;
      let rotatey = document.getElementById("rotatey").value;
      let rotatez = document.getElementById("rotatez").value;
      let translatex = document.getElementById('translatex').value;
      let translatey = document.getElementById('translatey').value;
      let translatez = document.getElementById('translatez').value;
      document.getElementById('box').style.transform = 
        "rotateX(" + rotatex + "deg) rotateY(" + rotatey + "deg) rotateZ(" + rotatez + "deg)"
      +"translateX("+translatex+"px) translateY("+translatey+"px) translateZ("+translatez+"px)";
      document.getElementById('rotatex-span').innerText = rotatex;
      document.getElementById('rotatey-span').innerText = rotatey;
      document.getElementById('rotatez-span').innerText = rotatez;
      document.getElementById('translatex-span').innerText = translatex;
      document.getElementById('translatey-span').innerText = translatey;
      document.getElementById('translatez-span').innerText =translatez;
    }
  </script>
</head>

<body>
  <div id="space">
    <div id="box">
    </div>
  </div>
  <div class="option">
    <p>rotate x: <span id="rotatex-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatex" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate y: <span id="rotatey-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatey" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate z: <span id="rotatez-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatez" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>translate x: <span id="translatex-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="translatex" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>translate y: <span id="translatey-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="translatey" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>translate z: <span id="translatez-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="translatez" value="0" class="range-control"
      onmousemove="change()" /><br />
  </div>
</body>

</html>

分别添加控制条的html内容以及再方法中添加控制代码,思路与添加rotate一致,

额外的在#box控制器中添加样式transtion: transform 1s liner;此代码使得图片滚动时产生动画效果

上面效果中图片的移动产生了动画的滑动效果,仔细的人会发现,当我们经过平移后,再转动图片,其转动效果不再围绕着图片进行旋转。原因在于,平移不会使得基点发生变化,对应的轴也不会发生改变

3.3实现旋转正方体 

这是最后的环节,通过上面的分析,我们发现问题其实已经解决了一大半,剩下的问题是,如何绘制一个正方体,当我们能够成功绘制出一个正方体,再通过上面的思路控制正方体的旋转平移即可

思路:(需要一些想象力,因为我找不到好的画图工具)假设如今有6块重叠在一起的面,每个面有1~6的标记用以区分,以这些面的中心点为基点,通过旋转和平移得到一个正方体,

  • 平面1向屏幕前移动一个单位(单位长度为正方体边长的一半)
  • 平面6向屏幕相反方向移动一个单位
  • 平面2沿着y轴逆方向旋转90°再往左平移一个单位
  • 平面5沿着y轴正方向旋转90°再往右平移一个单位
  • 平面3沿着x轴逆方向旋转90°再往上平移一个单位
  • 平面4沿着x轴正方向旋转90°再往下平移一个单位

此时,一个正方体就呈现了,通过上面思路完成最终代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>3Dbox</title>
  <style>
    #space {}

    #box {
      width: 180px;
      height: 180px;
      margin: 180px auto;
      transition: transform 1s linear;
      transform-style: preserve-3d;
      transform: rotateX(-35deg) rotateY(35deg);
    }

    .face {
      width: 180px;
      height: 180px;
      background-color: black;
      color: white;
      font-size: 180px;
      line-height: 180px;
      text-align: center;
      position: absolute;
      border: 1px solid white;
      opacity: 0.6;
    }

    #face1 {
      transform: translateZ(90px);
    }

    #face2 {
      transform: rotateY(-90deg) translateZ(90px);
      /* 当元素进行旋转后,其坐标轴会跟随改变 */
    }

    #face3 {
      transform: rotateX(90deg) translateZ(90px);
    }

    #face4 {
      transform: rotateX(-90deg) translateZ(90px);
    }

    #face5 {
      transform: rotateY(-90deg) translateZ(-90px);
    }

    #face6 {
      transform: translateZ(-90px);
    }

    .option {
      width: 700px;
      font-size: 16px;
      font-weight: bold;
      margin: 0 auto;
    }

    .range-control {
      width: 700px;
    }
  </style>
  <script>
    function change() {
      let rotatex = document.getElementById("rotatex").value;
      let rotatey = document.getElementById("rotatey").value;
      let rotatez = document.getElementById("rotatez").value;
      let translatex = document.getElementById('translatex').value;
      let translatey = document.getElementById('translatey').value;
      let translatez = document.getElementById('translatez').value;
      document.getElementById('box').style.transform =
        "rotateX(" + rotatex + "deg) rotateY(" + rotatey + "deg) rotateZ(" + rotatez + "deg)"
        + "translateX(" + translatex + "px) translateY(" + translatey + "px) translateZ(" + translatez + "px)";
      document.getElementById('rotatex-span').innerText = rotatex;
      document.getElementById('rotatey-span').innerText = rotatey;
      document.getElementById('rotatez-span').innerText = rotatez;
      document.getElementById('translatex-span').innerText = translatex;
      document.getElementById('translatey-span').innerText = translatey;
      document.getElementById('translatez-span').innerText = translatez;
    }
  </script>
</head>

<body>
  <div id="space">
    <div id="box">
      <div class="face" id="face1">1</div>
      <div class="face" id="face2">2</div>
      <div class="face" id="face3">3</div>
      <div class="face" id="face4">4</div>
      <div class="face" id="face5">5</div>
      <div class="face" id="face6">6</div>
    </div>
  </div>
  <div class="option">
    <p>rotate x: <span id="rotatex-span">-35</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatex" value="-35" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate y: <span id="rotatey-span">30</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatey" value="35" class="range-control"
      onmousemove="change()" /><br />
    <p>rotate z: <span id="rotatez-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="rotatez" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>translate x: <span id="translatex-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="translatex" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>translate y: <span id="translatey-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="translatey" value="0" class="range-control"
      onmousemove="change()" /><br />
    <p>translate z: <span id="translatez-span">0</span> deg</p>
    <input type="range" min="-360" max="360" id="translatez" value="0" class="range-control"
      onmousemove="change()" /><br />
  </div>
</body>

</html>

解析:

  <div id="space">
    <div id="box">
      <div class="face" id="face1">1</div>
      <div class="face" id="face2">2</div>
      <div class="face" id="face3">3</div>
      <div class="face" id="face4">4</div>
      <div class="face" id="face5">5</div>
      <div class="face" id="face6">6</div>
    </div>
  </div>

搭建正方体html,box里面对应6个面,通过css操作6个面的展示

    #box {
      width: 180px;
      height: 180px;
      margin: 180px auto;
      transition: transform 1s linear;
      transform-style: preserve-3d;
      transform: rotateX(-35deg) rotateY(35deg);
    }

transform-style:preserve-3d; 保证此元素的子元素能够使用3D效果,因为每个面要基于父元素基点做旋转平移操作

transform: rotateX(-35deg) rotateY(35deg); 给正方体一个初始角度

    .face {
      width: 180px;
      height: 180px;
      background-color: black;
      color: white;
      font-size: 180px;
      line-height: 180px;
      text-align: center;
      position: absolute;
      border: 1px solid white;
      opacity: 0.6;
    }

    #face1 {
      transform: translateZ(90px);
    }

    #face2 {
      transform: rotateY(-90deg) translateZ(90px);
      /* 当元素进行旋转后,其坐标轴会跟随改变 */
    }

    #face3 {
      transform: rotateX(90deg) translateZ(90px);
    }

    #face4 {
      transform: rotateX(-90deg) translateZ(90px);
    }

    #face5 {
      transform: rotateY(-90deg) translateZ(-90px);
    }

    #face6 {
      transform: translateZ(-90px);
    }

给每个面设置样式,根据思路布置好每个面的位置

至此,一个旋转正方体demo已经全部完成

4.关于平移与旋转的一些想法

本人在实践代码时,一开始被这些旋转和平移效果搞得混乱,在实现一些平移的时候,发现并不如己所愿,仔细观察最终效果图,会发现当我拉扯x轴平移、y轴平移,是不会水平平移,竖直平移的,原因在上文有提及,当旋转图形后,坐标轴会跟随旋转,那么能不能使得平移和旋转分开呢?使得当我们旋转的时候,只是绕着正方体中心旋转,当我平移的时候,任何时候都是水平,竖直平移。经过实践,答案是可以。

思路:设置两个坐标系,使得平移和旋转不在同一个坐标系,在box外层套一层盒子,以外层盒子作为平移坐标系,问题随即解决

最终效果:

因为以外层作为坐标系,外层与屏幕平行,且不对外层旋转,所以对于Z轴的平移,不会看到效果,故不添加到代码中,感兴趣的朋友可以尝试添加

代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>3Dbox</title>
  <style>
    #space {
      transition: transform 1s linear;
      transform-style: preserve-3d;
    }

    #box {
      width: 180px;
      height: 180px;
      margin: 180px auto;
      transition: transform 1s linear;
      transform-style: preserve-3d;
      transform: rotateX(-35deg) rotateY(35deg);
    }

    .face {
      width: 180px;
      height: 180px;
      background-color: black;
      color: white;
      font-size: 180px;
      line-height: 180px;
      text-align: center;
      position: absolute;
      border: 1px solid white;
      opacity: 0.6;
    }

    #face1 {
      transform: translateZ(90px);
    }

    #face2 {
      transform: rotateY(-90deg) translateZ(90px);
      /* 当元素进行旋转后,其坐标轴会跟随改变 */
    }

    #face3 {
      transform: rotateX(90deg) translateZ(90px);
    }

    #face4 {
      transform: rotateX(-90deg) translateZ(90px);
    }

    #face5 {
      transform: rotateY(-90deg) translateZ(-90px);
    }

    #face6 {
      transform: translateZ(-90px);
    }

    .option {
      width: 700px;
      font-size: 16px;
      font-weight: bold;
      margin: 0 auto;
    }

    .range-control {
      width: 700px;
    }
  </style>
  <script>
    function changeRotate() {
      let rotateX = document.getElementById('rotatex-input').value;
      let rotateY = document.getElementById('rotatey-input').value;
      let rotateZ = document.getElementById('rotatez-input').value;
      document.getElementById('box').style.transform =
        "rotateX(" + rotateX + "deg) rotateY(" + rotateY + "deg) rotateZ(" + rotateZ + "deg)";
      document.getElementById('rotatex-span').innerText = rotateX;
      document.getElementById('rotatey-span').innerText = rotateY;
      document.getElementById('rotatez-span').innerText = rotateZ;

    }
    function changeTranslate() {
      let translateX = document.getElementById('translatex-input').value;
      let translateY = document.getElementById('translatey-input').value;
      document.getElementById('space').style.transform =
        "translateX(" + translateX + "px) translateY(" + translateY + "px)";
      document.getElementById('translatex-span').innerText = translateX;
      document.getElementById('translatey-span').innerText = translateY;
    }
  </script>
</head>

<body>
  <div id="space">
    <div id="box">
      <div class="face" id="face1">1</div>
      <div class="face" id="face2">2</div>
      <div class="face" id="face3">3</div>
      <div class="face" id="face4">4</div>
      <div class="face" id="face5">5</div>
      <div class="face" id="face6">6</div>
    </div>
  </div>
  <div class="option">
    <p>rotate X: <span id="rotatex-span">0</span> deg</p>
    <input id="rotatex-input" type="range" value="-35" min="-360" max="360" class="range-control"
      onmousemove="changeRotate()">
    <p>rotate Y: <span id="rotatey-span">0</span> deg</p>
    <input id="rotatey-input" type="range" value="35" min="-360" max="360" class="range-control"
      onmousemove="changeRotate()">
    <p>rotate Z: <span id="rotatez-span">0</span> deg</p>
    <input id="rotatez-input" type="range" value="0" min="-360" max="360" class="range-control"
      onmousemove="changeRotate()">
    <p>translate X: <span id="translatex-span">0</span> deg</p>
    <input id="translatex-input" type="range" value="0" min="-360" max="360" class="range-control"
      onmousemove="changeTranslate()">
    <p>translate Y: <span id="translatey-span">0</span> deg</p>
    <input id="translatey-input" type="range" value="0" min="-360" max="360" class="range-control"
      onmousemove="changeTranslate()">
  </div>
</body>

</html>

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值