css3实践之摩天轮式图片轮播+3D正方体+3D标签云(perspective、transform-style、perspective-origin)

  本文主要经过摩天轮式图片轮播的例子来说解与css3 3D有关的一些属性。javascript

  demo预览css

  1. 摩天轮式图片轮播 (貌似没兼容360 最好用chrome)
  2. 3D正方体chrome only
  3. 3D标签云(css3版 chrome only
  4. 3D标签云(js版 chrome only

前文回顾

  在前面的文章css3实践之图片轮播(Transform,Transition和Animation)中咱们简单地了解了css3旗下的transform、transition以及animation。回顾一下,transform主要是对元素进行拉伸、旋转、移动等等操做,transition能使元素从一种样式逐渐改变为另外一种的效果,而animation能使元素依次进行n种样式之间的变化。其实对我而言,感兴趣的仍是前二者,毕竟作动画不是css的强项。html

  本文demo主要涉及css3的perspective、transform-style、perspective-origin属性。java

perspective、transform-style、perspective-origin

  前两个属性是css3下实现3d效果必不可少的,为何这样讲,咱们经过例子来讲明。css3

  首先咱们根据demo须要写好基本的html文件,其中核心代码截图以下:git

  html结构主要有三层,#stage->#container->.img。stage表示3d大舞台,里面能够包含不少的3d容器(container),而容器内则是须要向“观众"呈现的拥有3d效果的东西(demo里是图片)。github

  • perspective

  这里隆重推出perspective属性,perspective能够解释成视距,通俗讲perspective值即视点(perspective-origin)到电脑屏幕的距离(z轴方向),值越小,用户与3D空间Z平面距离越近。若是没有设置perspective属性,元素就不会拥有3D效果,仿佛是从很远地方看到的一个视图(能够联想一下三视图)。web

    

  perspective有两种书写方式,第一种是写在舞台上,第二种是写在3d元素上,与transform的其余属性写在一块儿,代码分别以下:chrome

#stage {
  width: 805px;
  height: 600px;
  border: 1px solid;
  -webkit-perspective: 500px;
  -webkit-perspective-origin: 17% 50%;
}
img {
  position: absolute;
  top: 110px;
  -webkit-transform: perspective(600px) rotateY(45deg);
}

  第二种也就是使得每一个3d元素都有视点(默认为元素中心),我以为几乎用不到,毕竟动画特效都须要模拟人眼看到的结果,也就是一个视点。app

  两种方式对比能够猛戳张鑫旭写的demo:猛戳这里 感谢做者~

  • perspective-origin

  与perspective关系密切的还有它的好兄弟perspective-origin,perspective解释为视距,那么perspective-origin就是视点。perspective-origin属性可空缺,默认为perspective-origin: 50% 50%,即从舞台(stage)中央看起(若是perspective属性加在stage的话),而perspective-origin和perspective通常同时出现(即加在同一个元素的css下),具体取值方法可参考CSS3 transform-origin 属性

  实例代码可参考perspective实例代码

  • transform-style

  transform-style和perspective同样重要,两者缺一不可。其中flat值为默认值,表示全部子元素在2D平面呈现。preserve-3d表示全部子元素在3D空间中呈现。沿着X轴或Y轴方向旋转该元素将致使位于正或负Z轴位置的子元素显示在该元素的平面上,而不是它的前面或者后面。若是对一个元素设置了transform-style的值为preserve-3d,它表示不执行平展操做,他的全部子元素位于3D空间中。既然咱们都说要实现3d效果了,通常取值固然是preserve-3d了!

  transform-style属性须要设置在3d动画元素的父元素中,而且高于任何嵌套的变形元素。实例代码:

#container {
  position: absolute;
  width: 500px; 
  height: 500px;
  -webkit-transform-style: preserve-3d;
  -webkit-transition: all 2s ease-in-out;
}
  • backface-visibility

  顾名思义,就是决定元素旋转背面是否可见。以下分别是有没有将demo里的3d元素的backface-visibility属性设置成hidden的结果:

    

  实例代码(对应第二张图):

img {
  position: absolute;
  top: 110px;
  -webkit-backface-visibility: hidden;
}

 

  小结:因此之后若是要写3d效果的css元素,只要像demo同样在html文件中写好stage和container元素,而后在stage中加上perspective,再在container中加入transform-style:preserve-3d 基本就ok了。

关于摩天轮式图片轮播

  先写好#stage->#container->.img形式的html文件,加上perspective和transform-style属性,9张图片分享360度,可以使每张图片围绕x轴旋转40*i度角:

  而后每张图片再设置translateZ的值,就会使得图片分开来围成圈:

var imgs = document.getElementsByTagName('img');
for(var i = 0; i <= 8; i++) {
  var deg = 40 * i;
  imgs[i].style.webkitTransform = ''
  + 'rotateX(' + deg + 'deg)' 
  + 'translateZ(' + 190 + 'px)'
  + 'scale(0.25,0.25)';
}

  最后再加上鼠标滚轮事件,每次滚动使得container元素总体绕x轴转动指定角度就好了,固然转动过程还须要transition的帮助:

var containerDeg = 0;
window.onmousewheel = document.onmousewheel = function(e) {
  containerDeg += e.wheelDelta / 15 ;
  document.getElementById('container').style.webkitTransform = 'rotateX(' + containerDeg + 'deg)' 
}

  有一点值得注意,就是原始图片的中心和container的中心要一致,只需设置图片(position:absolute)的left和top值就能够了。

  完整源代码可参考:源码请猛戳

关于3D正方体和3D标签云

  3D正方体和3D标签云(css3版)实现方式和图片轮播类似,都是在源点绕x轴和y轴旋转必定角度后,利用translateZ这个方法围绕源点分散开去。

  • 3D正方体

  设置6个长宽同样的div,而后分别绕x和y轴旋转须要的角度后,设置相同的translateZ值(为了方便写在js里了,也能够直接算出值写在css里):

// init
var initAngleX = [0, 180, 90, 270, 0, 0];
var initAngleY = [0, 0, 0, 0, 90, 270];
var angleX = 0;
var angleY = 0;
// container的旋转角度
var totalAngleX = 0;
var totalAngleY = 0;

for(var i = 0; i < 6; i++) {
  var d = document.createElement('div');
  d.style.backgroundColor = '#' + ('00000' + parseInt(Math.random() * 0xffffff).toString(16)).slice(-6);
  d.className = 'face';
  d.style.webkitTransform = ''
    + 'rotateX(' + initAngleX[i] + 'deg)' 
    + 'rotateY(' + initAngleY[i] + 'deg)' 
    + 'translateZ(' + 50 + 'px)';
  document.getElementById('container').appendChild(d);
}

  而后为了效果添加旋转,这里直接设置setInterval函数改变整个container的旋转角度了:

// addListener
document.getElementById('container').addEventListener("mousemove" , function(event){
  var x = event.clientX - 200;
  var y = event.clientY - 200;
  window.angleY =  x / 10 / 1000 * 60;
  window.angleX = -y / 10 / 1000 * 60;
});
 
setInterval(function() {
  totalAngleX += angleX;
  totalAngleY += angleY;
  document.getElementById('container').style.webkitTransform = ''
    + 'rotateX(' + totalAngleX + 'deg)' 
    + 'rotateY(' + totalAngleY + 'deg)';
}, 1000 / 60);

  你也能够将效果直接写在css上,好比设置个伪类(:hover),里面写好改变的css,而后设置下transition就ok了。

  • 3D标签云

  作了两个版本的,js版和css3版,不过其实都要用到js,只是后者的核心是css3。

  先来回顾一下js版本,或许js版本更适合实际使用,确实如此,现实中相似的3d标签云基本上都是js实现的。js版本的核心是获取平均分配在一个球面上的n个点的3维坐标,而后将z轴扁平化降到二维进行绘制,球体旋转时得到新的坐标进行重绘,demo中则是进行a标签新的位置肯定。如需了解更多可参考我之前写的文章《rotate 3d基础

  js版本里扁平化中的“焦距”(focalLength)就是css3里的perspective。

  js版z轴扁平化代码:

focalLength = 300;
var scale = focalLength / (focalLength + this.pos3.z);
this.pos2.x = 150 + this.pos3.x * scale;
this.pos2.y = 150 + this.pos3.y * scale;
this.a.style.fontSize = 12 * scale;
this.a.style.color = 'rgba('+this.r+','+this.g+','+this.b+','+ Math.min(1, scale)+')';

  pos3是3d空间的位置,而pos2是2d的位置,利用的是三角形类似(近大远小):

  屏幕位置和成像位置的距离就是3d物体的z值大小。

  而css3版本的则否则,省去了繁琐的3d->2d转换过程,a标签直接能进行3d变化。只是元素在进行旋转过程当中,a标签内的文字也没法控制地旋转。

  具体就不展开了,有兴趣的能够参考源码:猛戳这里

  之前用js写过的3d特效(猛戳demo1 demo2 demo3),其实也能够用css3实现,核心的函数就是rotate和translate!有兴趣的能够试一试。

总结

  总的来讲,若是要使dom元素呈现3d效果,perspective和transform-style属性的设置是必不可少的。

  由于上面一篇文章有园友反映没作兼容,本文的图片轮播demo我还特意作了兼容(ff下的渲染真是渣...),可是仍是没能兼容360,也不知道什么缘由,反正作兼容很蛋疼就是了,之后仍是有需求的时候再作兼容吧...

  楼主对以上理解尚不深刻,若有问题欢迎交流指导。

  参考文章:

  1. Transform-style和Perspective属性
  2. 好吧,CSS3 3D transform变换,不过如此!
  3. 理解:translate rotate 与 perspective 暧昧关系
相关文章
相关标签/搜索