好吧,CSS3 3D transform变换,不过如此!

这篇文章发布于 2012年09月7日,星期五,01:05,归类于 CSS相关。 阅读 862961 次, 今日 71 次 407 条评论

 

一、写在前面的秋裤

早在去年的去年,我就大肆介绍了2D transform相关内容。看过海贼王的都知道,带D的家伙都不是好惹的,2D我辈尚可以应付,3D的话,呵呵,估计我等早就在千里之外被其霸气震晕了~~

看看下图女帝的动作以及神情,就可以知道名字带D的家伙的厉害!
路飞女帝D族的厉害 张鑫旭-鑫空间-鑫生活

最近折腾iPad的一些东西,有一些3D效果的交互。有些事情,总以为是遥远的未来,谁知真正发生的时候说来就来,比如说一颗想结婚的心,又比方说在实际项目中折腾3D transform效果。

哭泣鑫表情 张鑫旭-鑫空间-鑫生活

然而,虽然以前折腾过3D变换效果(webkit),但都是依葫芦画瓢,囫囵吞枣,真正要轻松实现想要的3D效果,是需要深入理解的,于是,此时的自己苦逼了,泪奔ing……

木有办法,找资料,自己思考学习呗,当我看到下面这张基本图的时候,我的右侧的浓眉毛不由自主抖动了两下,呵,呵呵~~
3D变换坐标图解 张鑫旭-鑫空间-鑫生活

这个长得像原子核一样的是什么东东?那像章鱼哥一样四处横生的箭头好吓人哦!后面怎么还有一个苍蝇拍?? CSS好可怕,我要回去找妈妈……

想必大部分的同行应该跟我一样,没有爱因斯坦爷爷的智商,没有上镜需要把表摘掉的爸爸。因此,那些术语连篇的CSS3 3D transform介绍的资料过于耀眼,无法直视。怎么办?

好吧,佛家有云,我不入地狱谁入地狱。这里,我就从凡人们的视角说说CSS3 3D transform的一些东西,希望说的东西比较亲民,不要吓着大家。

二、首先,情感化认识

我觉得吧,要想理解一个东西,最好先有一些感性的认识。

CSS3中的3D变换效果,本质上就是我们OOXX时候各种姿势的变换,又称各种体位的变换。

虽然都是成年人,但考虑到仍有不少窝中待守的雏鸟,如果上面的解释想不过来,就想想以下这些:
1. 下图的这些人在干嘛?

跳水?NO, No, No!! 记住,他们不是在跳水,是在做3D变换!!!

2. 下图可爱baby在干嘛

广播体操?NO, No, No!! 记住,他不是在做操,是在做3D变换!!!

3. 来到2次元,下图这个妹子在这幅姿态称为:
鑫表情 性感 色
卖萌?NO, No, No!! 记住,他不是在卖萌,是在做3D变换!!!

哈哈哈哈,是否意识到:在现实世界中,一切的动作,都是属于3D transform变换。 因此,要学习与理解3D transform变换很简单,一句话,到现实世界找个东西映射一下即可。

三、认识的突破口:rotateX, rotateY, rotateZ

3D transform中有下面这三个方法:

  • rotateX( angle )
  • rotateY( angle )
  • rotateZ( angle )

理解了这三个方法,后面更难懂的perspective就好下手了,可以说是突破口!

rotate旋转的意思,rotateX旋转X轴,rotateY旋转Y轴,rotateZ旋转Z轴……

什么X轴/Y轴/Z轴,这几个词从我嘴里一出来,别说你们,我自己都晕了~~

赶快,从现实世界找对应东西理解(参照下面人的旋转):
邹凯的体操单杠运动是rotateX
单杠

蔡依林姐姐的钢管舞是rotateY
蔡依林-钢管舞 张鑫旭-鑫空间-鑫生活

旋转飞刀的特技表演是rotateZ
飞刀魔术

还是理解不过来?好吧,假设你是男的,以你的女朋友举例,假如原本你和她面对面站着,然后你——
从正面将其推到就是rotateX
妹子推到与transform rotateX 张鑫旭-鑫空间-鑫生活

让其原地转个90度欣赏其侧面的丰满曲线就是rotateY
妹子推到与transform rotateY 张鑫旭-鑫空间-鑫生活

把妹子抱到床上侧面躺着就是rotateZ
妹子推到与transform rotateZ 张鑫旭-鑫空间-鑫生活

于是,下面CSS世界中的简单3D效果是不是更容易理解了呢?!
transform rotateX(45deg)的效果图 张鑫旭-鑫空间-鑫生活 transform rotateY(45deg)的效果图 张鑫旭-鑫空间-鑫生活 transform rotateZ(45deg)的效果图 张鑫旭-鑫空间-鑫生活

四、必不可少的perspective属性

perspective的中文意思是:透视,视角!

perspective属性的存在与否决定了你所看到的是2次元的还是3次元的,也就是是2D transform还是3D transform. 这不难理解,没有透视,不成3D.

我们初中学美术,或者学建筑的同学肯定接触过透视的一些东西:
3D透视 张鑫旭-鑫空间-鑫生活 3D透视 张鑫旭-鑫空间-鑫生活

不过,CSS3 3D transform中的透视的透视点与上面两张示例图是不同的:CSS3 3D transform的透视点是在浏览器的前方

或者这么理解吧:显示器中3D效果元素的透视点在显示器的上方(不是后面),近似就是我们眼睛所在方位!

比方说,一个1680像素宽的显示器中有张美女图片,应用了3D transform,同时,该元素或该元素父辈元素设置的perspective大小为2000像素。则这张美女多呈现的3D效果就跟你本人在1.2个显示器宽度的地方(1680*1.2≈2000)看到的真实效果一致!!
1680宽度像素显示器与3D transform视角大小示意 张鑫旭-鑫空间-鑫生活

五、translateZ帮你寻找透视位置

如果说rotateX/rotateY/rotateZ可以帮助理解三维坐标,则translateZ则可以帮你理解透视位置。

我们都知道近大远小的道理,对于没有rotateX以及rotateY的元素,translateZ的功能就是让元素在自己的眼前或近或远。比方说,我们设置元素perspective为201像素,如下:

perspective: 201px;

则其子元素,设置的translateZ值越小,则子元素大小越小(因为元素远去,我们眼睛看到的就会变小);translateZ值越大,该元素也会越来越大,当translateZ值非常接近201像素,但是不超过201像素的时候(如200像素),该元素的大小就会撑满整个屏幕(如果父辈元素没有类似overflow:hidden的限制的话)。因为这个时候,子元素正好移到了你的眼睛前面,所谓“一叶蔽目,不见泰山”,就是这么回事。当translateZ值再变大,超过201像素的时候,该元素看不见了——这很好理解:我们是看不见眼睛后面的东西的!

再生动的文字描述也不如一个实例来得直观,您可以狠狠地点击这里:translateZ方法辅助理解perspective视角demo

建议Chrome浏览器下访问,可以使用range控件,演示效果更赞,如下截图:-100时候最小,200时候超级满屏(垂直方向因特殊布局限制没有显示),250的时候因为元素已经在视点之外,因此是一片空白(看不见)。
translateZ -100像素最远距离最小显示 张鑫旭-鑫空间-鑫生活 translateZ 200像素时候超级大的显示 translateZ为250像素时候元素在视区之外,因此看不见是空白 张鑫旭-鑫空间-鑫生活

六、perspective属性的两种书写

perspective属性有两种书写形式,一种用在舞台元素上(动画元素们的共同父辈元素);第二种就是用在当前动画元素上,与transform的其他属性写在一起。如下代码示例:

.stage {
    perspective: 600px;
}

以及:

#stage .box {
    transform: perspective(600px) rotateY(45deg);
}

您可以狠狠地点击这里:perspective属性的两种书写demo

结果如下缩略图:
CSS3 transform perspective两种书写形式demo效果截图

从上图我们貌似可以看到,虽然书写的形式,属性名称不一致,但是,效果貌似是一样的~~果真是这样吗???

实际上不然,上面的demo上下两个效果之所以会一样,是因为舞台上只有一个元素,因此,发生了巧合,其正好表现一样了。如果,如果舞台上有很多个元素,则两种书写形式的表现差异就会立马显示出来了!

您可以狠狠地点击这里:舞台多元素下的perspective两种书写对比demo

demo页面效果缩略图如下(因背景色随机,可能与下图有差异):
不同transform perspective书写下的表现差异

好吧,图中的效果其实不难理解。上面舞台整个作为透视元素,因此,显然,我们看到的每个子元素的形体都是不一样的;而下面,每个元素都有一个自己的视点,因此,显然,因为rotateY的角度是一样的,因此,看上去的效果也就一模一样了!

关于Chrome浏览器以及透视盲区
在Chrome浏览器下,要想看到完整的3D效果,还需要3D变换元素正好在窗体的垂直居中位置,因此,在Chrome浏览器下,生成了两个位置居中的按钮,帮助您看到想要的效果:
Chrome浏览器下位置居中按钮 张鑫旭-鑫空间-鑫生活
Chrome浏览器下舞台垂直居中3D效果显示

当我们改变第一个range控件值为200的时候,您会发现右侧第三个元素看不见了:
200值的时候有元素看不见

这不难理解,前面一排门,每个门都是1米,你距离门2米,显示,当所有门都开了45°角的时候,此时,距离中间门右侧的第二个门正好与你的视线平行,这个门的门面显然就什么也看不到。这就是为什么上面右侧第三个门一片空白的元素——特定的视角以及距离形成的视觉盲区。

七、理解perspective-origin

perspective-origin这个属性超级好理解,表示你那眼睛看的位置。默认就是所看舞台或元素的中心。有时候,我们对中心的位置是不感兴趣的,希望视线放在其他一些地方。比方说(见位置和百分比示意):
不同视线落地位置对应不同的perspective-origin值

下面为立方体的实际应用透视效果图:

perspective-origin: 25% 75%;

立方体不同透视角度的效果 张鑫旭-鑫空间-鑫生活

八、transform-style: preserve-3d

transform-style属性也是3D效果中经常使用的,其两个参数,flat|preserve-3d. 前者flat为默认值,表示平面的;后者preserve-3d表示3D透视。

preserve-3d符合我们真实世界的思维认识。比方说,你让妹子右转了45度,此时妹子脑袋左转45度想你吐舌卖萌,妹子的脸蛋应该和你是面对面平行的。
妹子推到与transform rotateY 张鑫旭-鑫空间-鑫生活
应用transform-style: preserve-3d声明的元素确实是这样表现的,但是,如果使用默认的flat值,其效果表现——恕我想象力有限——想不通:妹子的脸还是左转45度的,同时脑袋似乎移到了身体以外的地方

因此,基本上,我们想要根据现实经验实现一些3D效果的时候,transform-style: preserve-3d是少不了的。一般而言,该声明应用在3D变换的兄弟元素们的父元素上,也就是舞台元素。

九、backface-visibility

在显示世界中,我们无法穿过软妹A看到其身后的软妹B或C或D;但是,在CSS3的3D世界中,默认情况下,我们是可以看到背后的元素!
看不到后面的软妹,哦呵呵,  backface-visibility, 张鑫旭-鑫空间-鑫生活

因此,为了切合实际,我们常常会这样设置,使后面元素不可见:

backface-visibility:hidden;

十、实际应用-图片的旋转木马效果

您可以狠狠地点击这里:图片的旋转木马效果demo

建议在足够新版本的FireFox浏览器或Safari浏览器下观看,Chrome可能需要居中定位查看,下图为效果缩略图:

图片3D旋转木马效果截图

原理:
那些看上去很酷酷的CSS3 3D效果其实就颠来倒去那几个属性(本文提到的这几个),折腾来折腾去,这里这个效果显然也是如此。

首先HTML结构,如下:

舞台
    容器
        图片
        图片
        图片
        ...

对于舞台,很简单,加个视距,比方说800像素:

 perspective: 800px;

对于容器,很简单,加个3D视图声明,如下:

transform-style: preserve-3d;

然后就是图片们了。为了不至于产生类似DNA的螺旋状效果,我们让所有图片position:absolute,公用同一个中心点。

显然,图片旋转木马是类似钢管舞旋转的运动,因此,我们关心的是rotateY的大小。

因为要正好绕成一个圈,因此,图片rotateY值正好0~360等分,于是,如果有9张图片,则每个图片的旋转角度累加40(360 / 9 = 40)度即可。因此有:

img:nth-child(1) { transform: rotateY(   0deg ); }
img:nth-child(2) { transform: rotateY(  40deg ); }
img:nth-child(3) { transform: rotateY(  80deg ); }
img:nth-child(4) { transform: rotateY( 120deg ); }
img:nth-child(5) { transform: rotateY( 160deg ); }
img:nth-child(6) { transform: rotateY( 200deg ); }
img:nth-child(7) { transform: rotateY( 240deg ); }
img:nth-child(8) { transform: rotateY( 280deg ); }
img:nth-child(9) { transform: rotateY( 320deg ); }

这样就好了吗?

No, No, No!!!

想想看那,虽然9个绝色美女每个人的方位不一样,但都站在同一个点上,早就挤作一团,显然是不行的(见下图只设置rotateY)!我们需要拉开空间~~

只设置rotateY时候,众多美女图片挤作一团

如何拉开空间,很简单。

想想看那:9个美女,分别面朝东南西北共9个不同方位,她们只要每个人向前走个4~5步,美女们之间的空间不久拉开了,呈现圆形了!想象一下夜空中,礼花绽开的场景~~

这里的向前走4~5步,聪明的人应该已经知道了,就是本文提到的translateZ, 当translateZ为正值的时候,元素会向其面对的方向走去;如果元素无旋转,就会朝显示器走来!!

现在只剩下一个问题了,美女们要向前走多远呢??

这个距离是有计算公式滴!

拿本demo距离,每张美女图片的宽度是128像素,因此,有如下理想方位效果图:
旋转木马效果理想方位图 张鑫旭-鑫空间-鑫生活

上图中红色标注的r就是的demo页面中图片要translateZ的理想值(该值可以让所有图片无缝围成一个圆)!

r的计算很简单,有初中数学水平的人应该都会:

r = 64 / Math.tan(20 / 180 * Math.PI) ≈ 175.8

demo页面为了好看,图片之间留了点间距,使用的translateZ的值为175.8 + 20 = 195.8.
旋转木马demo页面translateZ值大小

最后的最后,要让木马旋转起来,只要让容器每次旋转40度就可以了。

节省篇幅,具体的JavaScript操作代码就不展示了,您有兴趣可以查看demo页面源代码。

理解了旋转木马3D效果实现原理,基本上,其他些3D效果可以轻松驾驭了,因此,本效果还是值得你花功夫看看滴~~

补充于2018-07-10
新增3D动画案例,实现2个3D开门效果,有完成源代码,有兴趣可以点击这里:“CSS3实现3D开门动画效果”。

十一、好吧,结语

理论上,现实世界,及3次元世界中的各种有规律的运动效果都可以使用CSS3 transform 3D方法实现。文章最后的旋转木马效果可以说是各类千奇百怪效果中的沧海一粟~~其他各类有的没有的效果就靠你的大脑就构想了。至于实现嘛,理解了,也就都是小菜。但是,要是不理解,纯粹从网上copy些效果代码,那永远就是copy的命咯!

文章篇幅已经很长了,我的指头也敲出老茧来了,就不再啰嗦什么了。希望本文的嗑叨、卖弄、折腾能够让您学习CSS3 3D transform变换的相关东西更加轻松点!

行文仓促,文中有错误在所难免,欢迎诸位指正。

(本篇完)

分享到:


发表评论(目前407 条评论)

  1. lmh说道:

    膜拜

  2. 筝小宇说道:

    膜拜大神5年前写的东西,感觉自己好惭愧!

  3. 永言说道:

    perspective 总算是 理解了~ 之前没搞清楚~ 我说怎么ios显示动画有问题,原来默认没有拉开视距~

  4. 小泽说道:

    已举报

  5. 码媛说道:

    emmmmmmmm ,妹纸表示 真的会有妹纸来看,这样真的好吗!!!!

  6. 赶路人说道:

    你有想过妹纸会看这个吗!!!

  7. 葫芦说道:

    66666请下渣渣的膝盖

  8. chg_miz说道:

    看了老司机文章后的理解:perspective的值就是视点(假想的人眼)离屏幕的垂直距离(201),translate的值就是元素离屏幕的垂直距离。translate=0时显示的元素为预先设置的width、height值;translate=50时显示的是元素离屏幕50、离视点151时的效果,由于元素离视点更近了。所以假想的人看到的图像肯定比预先的width、height大,显示的就是这个效果;tr=201时,元素与人眼重合,满屏;tr=202时,元素离屏幕202,在假想人眼后1,于是看不到元素了。门的那个盲区同理。

  9. 偶滴个神啊说道:

    大大污妖王 老司机发车了。。

    上班时间 有点不好意思点开看啊。。。

  10. 滴滴滴说道:

    滴滴滴,老司机发车。

  11. 阿部说道:

    大大 你的博客也有妹纸看的 你这么污 ,,,,,,哈哈哈

  12. zl说道:

    感谢楼主,非常详细的一遍教程。学到了。

  13. winter说道:

    污炸了,楼主

  14. a说道:

    我捂住嘴不让自己笑出来 ,并顺便来了段bbox。

  15. zero说道:

    鉴定完毕楼主的审美正常,哈哈哈哈

    很有用谢谢楼主了

  16. 不耐操说道:

    老司机开车了

  17. Top说道:

    我的形象化理解: 人眼(a)、perspective (b)、页面(c)在z轴上 若perspective=201;则b与c相距201 translateZ好比c在这条直线上的移动距离。越大距b越近,从b看 从a(在b的后方)看向b c就越大。当translateZ大于 201时 ;c 就在 a和b之间。当然a要通过b才能看见c ;此时 c 不可见

  18. 牛牛说道:

    老司机,呱唧呱唧

  19. 999说道:

    好污

  20. wl说道:

    看几秒就想笑,就捂着嘴,怕忍不住就来回看其他文章。

  21. Jocsonme说道:

    楼主写得好详细,学习了,可惜IE使用不了啊,即使是高版本的IE。

  22. 说道:

    一上午看了几篇文章,有时候觉得幽默,有时候太过浮夸,不知道大神放这一堆的图片是为了增加技术文章的吸引力还是本身就是如此爱好,一千个读者,一千个张含韵,希望不要成为咪蒙那样的,为了写文章而写文章,忽略了技术。个人观点。

  23. 111说道:

    用了一堆图卡通图, 还不如不用,直接用案例就好了,

  24. css说道:

    perspective讲得模糊,没讲清楚,感觉有点摸棱两可的感觉

  25. 坂田银时说道:

    请教一下,进行rotate操作之后,坐标系是跟着一起旋转了吗?比如rotateX(90deg)之后,是不是Z轴就变成朝上了?

  26. 四不四傻说道:

    上班期间打开后,不自觉环顾了四周。

  27. 见习司机说道:

    生动形象,受益非浅,向老司机致敬!

  28. 大明说道:

    厉害了

  29. shuen说道:

    太佩服了 ,研究的好透彻

  30. 呱呱呱说道:

    做旋转木马效果的轮播组件,因为设置了translateZ所以图片实际的尺寸会被拉大,造成图片模糊的问题,请问有办法解决吗

    • 小强说道:

      想到有种方法,设置更大的图片 再缩小图片 让其大小没有变化 但是图片占用的像素大啦
      @include square(100% * 1.2);
      position: absolute;
      top:-(100% * (1.2 – 1)/2);
      left:-(100% * (1.2 – 1)/2);
      @include scale(1 / (1.2))

  31. 啊草说道:

    厉害了,老司机,12年就出来了这篇文章

  32. codyching说道:

    CSS3 3D transform的透视点是在浏览器的前方!VS 或者这么理解吧:显示器中3D效果元素的透视点在显示器的上方(不是后面)??一直觉得后句话不能理解,两者意思感觉不同,能解释解释吗,张老湿,哈哈哈

    • 晨晨说道:

      我也没看懂这个 perspective如何准确计算出translateZ之后元素的大小 还是没懂

  33. paperen说道:

    哈哈哈哈 写得太搞了 不得不点赞

  34. 小旭依然说道:

    老司机,很有意思

  35. 在safari浏览器中,加了 transform-style:3d出先的bug说道:

    在苹果的微信当中,要实现一个翻页的拼图效果,可是加上了transform-style: 3d;之后它的翻转不是正常设置的翻转了,而且不可以保存最后的翻转状态,求楼主给指点一下

  36. lnc说道:

    人才!全看懂了

  37. 牛老大啊说道:

    写的不错,很有新意,用黄色的思想武装头脑,楼主你淫了。

  38. hah说道:

    看完了只是看完了,没有明白什么意思,不够精准

  39. 啦啦啦说道:

    这技术讲的太污了…

  40. janing说道:

    强行开车的时候,领导来了,还好拿了个翻页的项目糊了过去

  41. 风逸说道:

    楼主在卖萌~23333

  42. Maple说道:

    内容不错,图片更不错

  43. visa说道:

    被老司机强行开车

  44. 梦蝶说道:

    能不能提供个demo啊

  45. perry说道:

    好污,内容不错。。。学习了!!

  46. yu说道:

    写的太棒了,效果图也比较真实,比较好理解,就是上班看有点不合适,美女图片太多了。。

  47. 合群的猫笑说道:

    楼楼辛苦啦!支持下 。刚刚楼楼带领大家踏过二次元的大门,撬开船长爷爷的宝箱找到干货了。鼓掌~嘟嘟嘟

  48. railsbug说道:

    能找到那么多大胸美女 我只能说 辛苦了

  49. RedSpite说道:

    呜呜呜呜呜呜呜呜 老司机发车啦

  50. steven说道:

    阿里嘎多