响应式的页面设计中,随着页面内容的增多,页面上可用的空间越来越少,尤其是在移动手机等小屏幕设备上,页面空间显得尤为重要。旋转木马和幻灯片是响应式网页展示图片的一个解决方案。但是我们想要更加优雅的展示图片方式:图片像折纸一样一张张的展开。这就是本篇文章我们要讲述的内容。
HTML结构
<div id="mm"> <img src="mm-center.jpg" alt> <img id="top" src="mm-top.jpg" alt> <img id="left" src="mm-left.jpg" alt> <img id="bottom" src="mm-bottom.jpg" alt> <img id="right" src="mm-right.jpg" alt> </div>
图片的名称对应于图片在这个3D折纸效果中的位置结构,以及它们展开的顺序:最后的图片将最先被折叠,然后是倒数第二张图片,以此类推。在容器div#mm
中的第一张图片mm-center.jpg
不会被移动。
CSS样式
在这个3D折纸效果中,图片都使用相同的尺寸,#top
和#bottom
两张图片使用photoshop将它们旋转了180度。接下来,我们要设置包裹容器div#mm
的响应式3D效果。
div#mm { width: 25%; position: relative; perspective: 1500px; margin: 0 auto; }
该容器中的元素将会随着容器的缩放而缩放,另外perspective
的值设置为一个合适的值。下面个图片一些样式:
div#mm img { position: absolute; max-width: 100%; -webkit-filter: drop-shadow(3px 3px 5px rgba(0,0,0,0.6)); filter: url(shadow.svg#drop-shadow); filter: drop-shadow(3px 3px 5px rgba(0,0,0,0.6)); transform: rotate3d(0, 0, 0, 0deg); transition-duration: 1s; }
图片使用标准的“绝对定位元素位于相对定位元素的里面”的定位方式。每一幅图片的transition
都持续1秒钟。在图片上还使用了dynamic drop-shadow来制作阴影效果,这种阴影效果将对Chrome、Safari 和 Firefox产生作用。和标准的box-shadow
属性不同,drop-shadow
可以准确的反应出3D动画时的阴影效果。
rotate3D Matrix
rotate3d
属性对于操纵3D对象时非常有用的:它的参数的最后的值会在元素旋转时被应用到X、Y和Z轴上。任何一个轴上的值为1表示在该轴上旋转100%,0.5表示在该轴上旋转50%,以此类推。
避免在webkit浏览器上过早的转换
在webkit内核的浏览器上制作动画有一个小问题:在页面加载后元素会从默认状态立刻过渡到最终状态,尤其是设置transition
属性为all
的时候。通过使用position: absolute
和设置rotate3d
全部为0,我们可以在Chrome 和 Safari浏览器中避免这种情况的出现。
创建3D折纸效果
当用户用鼠标滑过包裹容器的时候,图片开始展开动画。下面以第一幅图片的动画为例:
div#mm img#right { transform-origin: top right; transition-delay: 3s; } div#mm:hover img#right { transform: rotate3d(0, 1, 0, 180deg); transition-delay: 0s; }
每一幅图片的转换都是从图片的右上角开始的,图片在于用户交互是会沿Y轴翻转180度展开。
到目前为止,都是一些标准简单的3D transforms转换。这时,当鼠标离开包裹容器时,图片会展开的顺序重新折叠起来。这不是我们所需要的。我们需要的是先展开的图片后折叠。
为了制作这种效果,我们为图片的默认状态添加一个延时。请记住,transition-delay
总是会持续到下一个状态。
Motion | Delay before movement | Duration |
Unfolding (default state → hover state) | None (derived from the value on the :hover state) | 1 sec |
Refolding (hover state → default state) | 3 seconds (derived from the value on the default state) | 1 sec |
也就是说,在图片栈中,先展开的图片要设置一个较高的transition-delay
,这样,在往回折叠的时候,先展开的图片会等待更长的时间。
div#emma img#bottom { transform-origin: center bottom; transition-delay: 2.5s; } div#emma:hover img#bottom { transform: rotate3d(1, 0, 0, -178deg); transition-delay: .5s; } div#emma img#left { transform-origin: left top; transition-delay: 2s; } div#emma:hover img#left { transform: rotate3d(0, 1, 0, -178deg); transition-delay: 1s; } div#emma img#top { transform-origin: top center; transition-delay: 1.5s; } div#emma:hover img#top { transform: rotate3d(1, 0, 0, 179deg); transition-delay: 1.5s; }
上面的代码中,图片的旋转度数都在±180°之间,这是为了防止有些浏览器在顺时针或逆时针从0度旋转到180度时产生解析错误。使用不等于180度的值可以使各个浏览器都产生正确的结果。
小结
CSS 3D transforms可以让我们在页面上使用透视功能,使得元素可以往Z轴方向上生长,从而可以减少页面空间的占用。
这个3D折纸的效果做的还不是十分完美,在移动手机上,图片展开后不会折叠回去。而且也没有为不支持CSS transforms属性的浏览器写回退代码。
理想状态下,这个3D折纸效果的应该是双面的:在图片展开时看到的图片是和背面图片不同的。这也是待解决的问题。我们将在以后的文章中逐一解决这些问题。