原作者接受前端挑战后最后实现的效果:http://rdcm.com/en/
译者:camiler 链接:http://www.zcfy.cc/article/872 原文:https://www.smashingmagazine.com/2016/07/front-end-challenge-accepted-css-3d-cube/
分享我使用CSS 3D效果的经历,那是第一次用于实际项目中,以此来激励你接受挑战。
那是平常的一天,当Eugene( CreativePeople的经理)写信给我的时候。他寄给我一个视频,说他正在为一个新项目开发一个概念,而且想知道我是否可能开发一个像视频里那样的东西。
这是一个绕着一个轴旋转的3D物体(准确地说是个立方体)。对于用CSS 3D工作我已经有一些经验了,于是我的脑海里开始形成一个解决方案。我Google搜索了像“CSS 3D cube”这样的关键词来确认我的想法,随后我回复Eugene说我可以。
Eugene下一个问题是问我是否愿意承担这个项目?我喜欢复杂的任务,所以我不能拒绝。在这一刻,我还没有意识到我正陷入其中,但我无法确定是否可以完成。
理解轴(字面翻译是磨斧)
提醒下这个axes不是战斧,而是 数轴的意思,正如我们在学校学到的三维直角坐标系一样的轴线。维基百科定义:
直角坐标系是一个两两垂直有序的三元线行成的三维空间,三条轴都有一个单独的单位长度并且每一条轴线有一个方向。
下面的图片展示了在Web浏览器中怎样确定轴线方向。
一个以z轴朝向观察者的右手三维直角坐标系。 (图片来自: 维基共享资源)。
x
轴平行,y
轴垂直,z
轴指向正对你的屏幕。z轴的零点就是屏幕所在的平面。记住这一点。
理解透视值
要创建一个3D物体,我需要一个具有透视效果的元素(我们称之为“scene”)。透视大小就是这个场景的深度,并且它取决于它包含的物体大小。
如果透视距离太小,物体可能会被扭曲。如果太大,3D效果将减少到没有。
id="vKVrWL" src="http://codepen.io/airen/embed/vKVrWL?height=400&theme-id=0&slug-hash=vKVrWL&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd在 CodePen)上编写.
此外,在这个场景中对于所有物体而言只有一个视野角度。3D效果取决于观察点的位置。
id="bZmJYA" src="http://codepen.io/airen/embed/bZmJYA?height=400&theme-id=0&slug-hash=bZmJYA&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
x
轴,高度值乘以4
应该合适。对于y
轴,应该是宽度值乘以4
。这是我的魔法公式:
考虑所有侧面
div
创建,相对定位,宽度和高度都定义(200px
)。通过具有preserve-3d
值的transform-style
6
个绝对定位的div
(或者说是侧面)。类名相当于几个侧面(后面,左边,右边,上面,下面,前面)的初始位置。标记如下:
默认情况下,所有侧面都在一个平面上。所以,我需要将它们重新排列。演示如下:
id="xOyZPN" src="http://codepen.io/airen/embed/xOyZPN?height=400&theme-id=0&slug-hash=xOyZPN&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
由此产生CSS如下:
transform
属性值是X轴旋转任意角度:
克服缺点
x
轴旋转这个立方体,所以我不需要左侧或者右侧。我添加了标注来将剩下侧面的初始位置对齐。
我开始旋转立方体时发现底部和背面的标注说明都显示颠倒了:
id="OXBGzp" src="http://codepen.io/airen/embed/OXBGzp?height=400&theme-id=0&slug-hash=OXBGzp&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
x
轴旋转了180
度:
超越屏幕
1
个像素的虚线,但看起来很糟糕模糊。
id="rLqbpk" src="http://codepen.io/airen/embed/rLqbpk?height=400&theme-id=0&slug-hash=rLqbpk&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
我立马认识到问题出在哪了。你记得图片延伸到屏幕之外的3D TV广告么?这跟我这个立方体是同一回事。
z
轴的零点)并且正面超出了屏幕。因此,在视觉上增大了也模糊了。
id="EydJoJ" src="http://codepen.io/airen/embed/EydJoJ?height=400&theme-id=0&slug-hash=EydJoJ&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
为了解决这个问题,我沿着z轴移动这个立方体使得正面对齐到屏幕所在的平面:
现在,这个立方体准备的差不多了:
id="qNJwxW" src="http://codepen.io/airen/embed/qNJwxW?height=400&theme-id=0&slug-hash=qNJwxW&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
使用神奇数字
100
来沿着轴移动这些侧面。而100
这个值正好是我测试的立方体高度的一半。为什么是一半?因为那个值是立方体侧面(显然是一个正方形)一个内切圆的半径。
如果我需要旋转一个三棱柱,这个圆就是三角形的内切圆。这种情况下,偏移公式就会如下:
消除立方体
要想把任务完成,我必须在不同的浏览器中进行测试。 在IE中看到的画面让我陷入沮丧。为了让你知道我在说什么,在你最爱的浏览器中打开这个样例。我改变了一个属性导致在IE中这个立方体显示完全不正确。无论如何,不要偷看源码直到你读了在这个样例下面的那段文字。
id="OXBGQm" src="http://codepen.io/airen/embed/OXBGQm?height=400&theme-id=0&slug-hash=OXBGQm&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
preserve-3d
的transform-style
属性。通过查看可靠资源Can I Use(notes中第一点)我了解到这一点。在上面的样例中,我将preserve-3d
换成了flat
。你是不是已经知道了?哼!让你不要偷看了!
我很烦躁,但我并不打算放弃。遇到一个问题就是获得一次学习新东西的机会。再说,我已经接收了这次挑战。
寻找支点
transform-style: preserve-3d
来创建一个3D对象的方法,最终我发现一个有用的属性:transform-origin
。它决定了一个元素变换的中心点。我建了一个可以交互的样例,可以帮助你理解这个属性是如何工作的:
id="yJRAvq" src="http://codepen.io/airen/embed/yJRAvq?height=400&theme-id=0&slug-hash=yJRAvq&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
在这个例子中,元素的3D旋转是不是和立方体正面很像?这正是我要用的。
backface-visibility:hidden
么?这个属性用来在3D变换中隐藏元素的背面)。
重新出发
scene
元素的 perspective
属性然后将该属性添加到每个3D变换,这样每个元素的变换就是独立的了。同时,我给每个侧面设置了新属性:transform-origin
,其值是立方体中心的位置,以及backface-visibility: hidden
。样式改变如下:
transform-origin
属性,我不用再改变它们的位置,只需要围绕轴旋转它们。这就像魔术一样!我们来目睹一下它的神奇:
id="zBmXRb" src="http://codepen.io/airen/embed/zBmXRb?height=400&theme-id=0&slug-hash=zBmXRb&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
这些侧面位置的CSS如下:
这里你能看到在运行中的全新立方体:
id="VjENXv" src="http://codepen.io/airen/embed/VjENXv?height=400&theme-id=0&slug-hash=VjENXv&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
桥是桥路是路,做好自己的事
第二个立方体看起来旋转和第一个一样。但在这个例子中,你需要单独变换每一个侧面。这可能不太容易,尤其是你想控制旋转的中间角度。
此外,如果你在Chrome浏览器打开这个例子,会看到这些侧面在旋转的时候会闪烁,这让我感觉很沮丧。
transform-style: preserve-3d
属性的简单测试应用在这两个实现立方体的方式中。第一个立方体是默认的,第二个是针对IE浏览器以及不支持preserve-3d
的浏览器。
运用数学的力量
最终,我必须实现一个视差效果。通常,这种效果根据用户行为响应,无论是鼠标光标还是滚动条的位置。在这个例子中,这个效果取决于旋转的角度。
id="NAOmYw" src="http://codepen.io/airen/embed/NAOmYw?height=400&theme-id=0&slug-hash=NAOmYw&default-tab=result&user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="box-sizing: inherit; width: 940px; overflow: hidden;">
由Anna Selezniova (@askd 在 CodePen)上编写。
偏移量
。其次,我有它旋转的角度
。
我花了几个小时试图定义一个公式。随后,我恍然大悟。这就是我的灵感:
正弦余弦函数图 (图片: 维基共享资源)。
在正弦余弦函数的帮助下,通过角度我轻松地计算出了每个标注的偏移。这是我提出的公式:
总结
现在任务完成了,我很享受这个结果并且将它分享给你。看一下它展示的如何。使用鼠标滚动或者箭头键旋转广告块。同样,你也可以尝试拉出左边的黑三角上下拖动来手动控制旋转的角度(遗憾的是,这个特征在IE浏览器中无法工作)。看起来确实不错吧?而且性能也相当高(大概每秒60帧)。
我很高兴参与了这个网站的开发。在CSS 3D实践中我收获了宝贵的经验,并且发现了许多有意思的属性。更重要的是,我懂得了一个人不应该轻言放弃,很可能你会找到一个方法来完成。
我希望你喜欢我的故事,也希望你现在做好准备迎接新的挑战!