先展示研究成果:
今天想研究一下CSS的 3D实现,但又不敢深入三角函数和线性代数的知识(多年前就已还给高数老师了),所以就浅浅地从translateX/translateY/translateZ这3个变换做一个立方体开始。这三个变换函数很简单,关键是要建立固定的坐标系,这样页面的元素就能通过这个坐标系获得立体感。
我的HTML结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <div class="scene"> <!--方块--> <div class="cube"> <div class="cube-face cube-face-front">1</div> <div class="cube-face cube-face-right">2</div> <div class="cube-face cube-face-top">4</div> <div class="cube-face cube-face-left">3</div> <div class="cube-face cube-face-back">5</div> <div class="cube-face cube-face-bottom">6</div> </div> <!--坐标线--> <div class="line line-x"></div> <div class="line line-y"></div> <div class="line line-z"></div> </div> |
坐标线的样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | .line{ position: absolute; width: 500px; height: 1px; border-top: 1px dotted #000; background:transparent; /*坐标轴要围绕原点旋转,先定好transform-origin*/ transform-origin: 0 0; left:40%; top:60%; } .line-y{ /*x方向旋转获得y轴*/ transform: rotate(-90deg); } .line-z{ /*y方向旋转获得z轴*/ transform: rotateY(-90deg); } |
场景样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | .scene { position: relative; width: 700px; max-width:100%; height: 500px; border: 2px solid #CCC; /*这两个perspective属性直接决定视觉效果,诸位可以自己调整*/ perspective: 1600px; perspective-origin: 150% -40%; overflow: hidden; /*立方体的尺寸变量,在坐标中会多次用到负值,这里定义一正一负两个值是为了减少后面的运算*/ --cube-size: 100px; --cube-size-minus: -100px; transition: all 0.5s; } |
以上定义完毕后,获得场景,注意坐标原点位置为40%,60%:
接下来设置立方体的样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | .cube { width: var(--cube-size); height: var(--cube-size); position: absolute; /*位置放在原点*/ left: 40%; top: 60%; transform-style: preserve-3d; /*因要使立方体底部对其原点,所以必须向上偏移一个立方体高度*/ transform: translateY(var(--cube-size-minus)); transition: all 0.5s; } /*六个面统一样式*/ .cube-face { position: absolute; bottom: 0; left: 0; width: var(--cube-size); height: var(--cube-size); display:flex; flex-direction: row; justify-content: center; align-items: center; font-size: 40px; font-weight: bold; color: #fff; text-align: center; transform-origin: 0 100%; transition: all 0.5s linear; } /*六个面的颜色*/ .cube-face-front { background: rgba( 25, 175, 240, 0.8); } .cube-face-right { background: rgba( 134, 209, 204, 0.8); } .cube-face-back { background: rgba(189, 211, 225, 0.8); } .cube-face-left { background: rgba(225, 190, 135, 0.8); } .cube-face-top { background: rgba(240, 175, 25, 0.8); } .cube-face-bottom { background: rgba(25, 175, 240, 0.8); } /*六个面的位置,其中back这面正好对齐x和y轴原点面,无需翻转,其他个面,都是在back面基础上,通过rotate和translate复合翻转位移*/ .cube-face-back { } /*前面,仅朝着屏幕移近1个宽度,z轴负方向*/ .cube-face-front { transform: translateZ(var(--cube-size)); } /*右侧面,竖直方向翻转90度到屏幕里面去了,translateX移出来一个单位,再向右移一个单位到正确位置*/ .cube-face-right { transform: rotateY( 90deg) translateX(var(--cube-size-minus)) translateZ(var(--cube-size));} /*左侧面,竖直方向翻转90度到屏幕里面去了,translateX移出来一个单位*/ .cube-face-left { transform: rotateY( 90deg) translateX(var(--cube-size-minus)); } /*顶部,X轴方向翻转90度到屏幕里面去了,再上移,再移出*/ .cube-face-top { transform: rotateX( 90deg) translateY(var(--cube-size)) translateZ(var(--cube-size)); } /*顶部,X轴方向翻转90度到屏幕里面去了,再移出*/ .cube-face-bottom { transform: rotateX( 90deg) translateY(var(--cube-size)); } |
现在方块就形成了:
这是一个正立方体,假如要调整任意一个面的尺寸,保持它的完整,它就会变成长方体,其他各个面的尺寸也需要相应调整。这时候就借助一下JS:
//通过这个函数,可以完成立方体的任意尺寸变化 function resizeCube(l,w,h){ var cube_length = l; var cube_width = w; var cube_height = h; $(".cube-face-front").css("width" , cube_width+"px") $(".cube-face-front").css("height" , cube_height+"px") $(".cube-face-front").css("transform" , "translateZ("+cube_length+"px)") $(".cube-face-back").css("width" , cube_width+"px") $(".cube-face-back").css("height" , cube_height+"px") $(".cube-face-top").css("width" , cube_width+"px") $(".cube-face-top").css("height" , cube_length+"px") $(".cube-face-top").css("transform" , "rotateX( 90deg) translateZ("+cube_height+"px) translateY("+cube_length+"px)") $(".cube-face-bottom").css("width" , cube_width+"px") $(".cube-face-bottom").css("height" , cube_length+"px") $(".cube-face-bottom").css("transform" , "rotateX( 90deg) translateY("+cube_length+"px)") $(".cube-face-right").css("width" , cube_length+"px") $(".cube-face-right").css("height" , cube_height+"px") $(".cube-face-right").css("transform" , "rotateY( 90deg) translateZ("+cube_width+"px) translateX(-"+cube_length+"px)") $(".cube-face-left").css("width" , cube_length+"px") $(".cube-face-left").css("height" , cube_height+"px") $(".cube-face-left").css("transform" , "rotateY( 90deg) translateX(-"+cube_length+"px)") } |
以上都是基础原理,我后续又对整个程序做了一点点小变化,它就成了一个可以做一些随机变化的小玩具,见这个链接:https://blog.brain1981.com/wp-content/uploads/css-3d-cube.html
这个坐标系只是我的一个网站项目里要用到的小工具,因为只需要简单实现,就不想给页面加载任何庞大的JS库,于是自己研究了一下实现。再复杂的3D形状,都是通过一个个面形成的,我们可以用background-image给它们贴图,也可以增加任意个面构建复杂的形状,不过纯手工这样做是很累的,做复杂的项目,肯定还是要引入适合的库了。
本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.brain1981.com/2414.html。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。
本站记录了近几年的工作中遇到的一些技术问题和解决过程,“作品集”还收录了本人的大部分作品展示。除了本博客外,我们的工作室网站 – JennyStudio,内有更多作品回顾和展示。
您也可以扫描左边的二维码,关注我们的微信公众号,在微信上查看我们的案例。
您也可以扫描左边的二维码,关注我们的微信公众号,在微信上查看我们的案例。