原文:http://net.tutsplus.com/tutorials/html-css-techniques/build-a-kickbutt-css-only-3d-slideshow/
作者:Will Moyer
译者:蒋宇捷(http://blog.csdn.net/hfahe)
友情提示:本文难度为中等,阅读完需要45分钟,理解需要一定的基础。
下载源文件
示例在线观看
译者注:观看示例请使用最新版的Safari(5.0.3以上版本)或Chrome(10.0.648以上版本),Chrome需打开about:flags,开启“GPU加速合成”-使用图形处理器 (GPU) 硬件启用网页的 3D CSS 和更高性能的合成。
在这个教程里,我将要向你展示如何只使用HTML和CSS创建立体的幻灯片。完全不需要Javascript!开启Safari,我们出发了!
原理
在我们开始构造幻灯片之前,理解实现方法非常重要。我们将要使用CSS3新的属性-3D变换。你可能看过其他教程,教你使用这些变换在3D空间内创建动画物体。通常创建幻灯片时,我们依赖于Javascript以触发这些变换。Javascript可以检测到鼠标点击事件,然后更改某个HTML元素的属性(通常是添加一个类),更改的元素会拥有一个新的CSS类型。
这个教程不一样的地方在于,我们使用CSS代替Javascript来触发点击事件和更改元素的样式。Jeffrey Way最近撰写的快速技巧一文,描述了一种使用CSS的:target伪类来模仿点击事件的方法。这里我们将使用到:focus伪类和HTML5的标签<figcaption>,但是原理是一样的。这个方法不一定比使用Javascript更佳,但是用到了HTML最新标签的特性,是一个简洁的选择。
准备:快速开始
让我们从创建一个index.html和style.css开始。我们还需要创建一个名为images的文件夹。我们的3D物体将会是一个六面体,四面是940像素宽、400像素高,另外两面是400像素宽、400像素高。我在源文件中包含了6幅图像,把它们或者你自己的文件放在images文件夹下。
第一步:HTML页面
下面是我们基础的HTML代码。我们将所有的的元素和我们的幻灯片放在一个名为container的容器里。自然还需要创建一个名为slideshow的div元素。
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"> <title>CSS 3D Slideshow</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="container"> <div id="slideshow"> </div> </div> </body> </html>
在slideshow里为六幅图像创建如下代码:
<figure id="box"> <img src="images/face1.jpg"/> <img src="images/face2.jpg"/> <img src="images/face3.jpg"/> <img src="images/face4.jpg"/> <img src="images/face5.jpg"/> <img src="images/face6.jpg"/> </figure>
请注意到我们的图像(3D物体的六面)放在一个id为box的<figure>标签内。这个就是我们在幻灯片动起来时需要旋转的元素。
诀窍
现在允许我们只使用CSS来检测事件点击的秘诀来了。我们使用另外6个<figure>标签来包围box。每一个<figure>为我们3D物体描绘一个不同的旋转方式。属性tabindex允许这些元素接收伪元素:focus。每一个<figure>内部也需要一个<figcaption>元素。这些<figcaption>标题将为我们的按钮服务。当我们点击按钮时,这些标题将会触发父元素<figure>来接收:focus。这样我们可以在box上使用6个不同的CSS转换。以上可能听起来有点复杂,但是一旦我们看到CSS就会很容易明白。现在,只需要使用6个<figure>包围box,同时给每一个定义一个不同的tabindex和id。然后为每一个<figure>包含一个<figcaption>元素。
最后的HTML
Index.html最后看起来就像这样:
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"> <title>CSS 3D Slideshow</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="container"> <div id="slideshow"> <figure tabindex=1 id="fig1"> <figcaption>Side 1</figcaption> <figure tabindex=2 id="fig2"> <figcaption>Side 2</figcaption> <figure tabindex=3 id="fig3"> <figcaption>Side 3</figcaption> <figure tabindex=4 id="fig4"> <figcaption>Side 4</figcaption> <figure tabindex=5 id="fig5"> <figcaption>Side 5</figcaption> <figure tabindex=6 id="fig6"> <figcaption>Side 6</figcaption> <figure id="box"> <img src="images/face1.jpg"/> <img src="images/face2.jpg"/> <img src="images/face3.jpg"/> <img src="images/face4.jpg"/> <img src="images/face5.jpg"/> <img src="images/face6.jpg"/> </figure> </figure> </figure> </figure> </figure> </figure> </figure> </div> <!-- End Slideshow --> </div> <!-- End Container --> </body> </html>
第二步:基本的CSS
首先,让我们打开style.css并粘贴进一些初始的代码(移除:focus会导致的outline非常重要)。
/* RESET */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } :focus { outline: 0; } /* HTML5 tags */ header, section, footer, aside, nav, article { display: block; }
现在,我们给页面一个漂亮的渐变背景。
html { width: 100%; height: 100%; background-color: #FFFFFF; background-image: -moz-linear-gradient(top, #FFFFFF, #b3b3b3); background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #FFFFFF),color-stop(1, #b3b3b3)); filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#b3b3b3'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#b3b3b3')"; }
Background-image属性带上了Mozilla和Webkit的前缀。如果你想要一个支持IE的版本,filter和-ms-filter属性将为IE6、7、8创建渐变(我在常用的站点www.css3please.com上构建了这些代码)。
现在,让我们为我们的container、slideshow和盒子加上一些样式。
#container { width: 960px; margin: 0 auto; } #slideshow { width: 900px; margin: 50px auto 0 auto; padding: 50px 0 0 0; } figure { display: inline; } #box { position: relative; display: block; width: 900px; height: 400px; }
我们的container,宽度为960像素,通过margin: 0 auto来实现居中。Slideshow div会有900像素宽,居中放置,距离页面顶部50像素。我们还为它在顶部设置50个像素的padding边距。Padding所在区域将会包含我们slideshow的按钮- <figcaption>元素,一旦我们为它们指定了位置。
实际上包含我们slideshow的元素-box,被设置为和我们图片一样的大小。将它的position属性设置为relative非常重要,因为我们将要把它的一些子元素设置为绝对定位。我们另外的<figure>元素将会被设置为display:inline,但是box元素需要设置为display:block。
现在,设置我们6幅图像的样式。
#box img { position: absolute; top: 0; left: 0; }
我们将所有的图像定义为绝对定位,它们将会在box的左上角上一副一副的叠在一起。(top和left缺省都是0,为了更加清晰我们还是进行了定义)现在,我们的slideshow看起来像是这样。
让我们为 <figcaption>按钮添加一些样式。
figcaption { display: inline-block; width: 70px; height: 35px; background: rgba(0,0,0,0.6); border: 1px solid rgba(0,0,0,0.7); -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; text-align: center; line-height: 35px; color: #ffffff; text-shadow: 1px 1px 1px #000000; cursor: pointer; position: relative; top: -50px; left: 150px; margin: 0 30px 0 0; -moz-transition: all 0.1s linear; -o-transition: all 0.1s linear; -webkit-transition: all 0.1s linear; transition: all 0.1s linear; }
以上样式的第一段相当富有美感,它使按钮半透明、具有圆角、文字居中同时还有阴影。它还使鼠标指针变为手型,用户知道可以点击。
“确保按钮在6个<figure>元素的边界之外。否则,点击按钮实际上是在最里面<figure> 上注册了一个点击事件,而不是对应到按钮的那一个。”
最后一点代码添加变换。因为我们将要为<figcaptions>的鼠标hover状态添加样式。
figcaption:hover { background: rgba(0,0,0,0.8); }
我们定义好的按钮看起来像如下一样:
第三步:3D容器
第一件要完成的事情是告诉浏览器我们需要一个3D空间。我们通过在父元素slideshow上使用perspective属性来完成(加上-webkit前缀)。
#slideshow { width: 900px; margin: 50px auto 0 auto; padding: 50px 0 0 0; -webkit-perspective: 800; /* triggers a 3D space */ }
Perspective属性的值决定3D物体透视范围大小,值越大3D效果越夸张。
我们还需要将3D空间贯穿到所有的子元素上。我们将通过为所有的<figures>添加transform-style: preserve-3d属性来实现(我们又一次使用了webkit前缀)。
figure { display: inline; -webkit-transform-style: preserve-3d; /* maintains 3D space */ }
好吧,开始转换每一面来创建3D盒子的时候到了。我们将通过nth-child伪类来选定每一幅图像,但是为每一幅<img>指定一个id也是同样可行的。确保你在样式表的当前样式下面添加这些代码。
如下是代码,我会在下面解释它。
#box img:nth-child(1) { -webkit-transform: rotateX(0deg) translateZ(200px); } #box img:nth-child(2) { -webkit-transform: rotateX(180deg) translateZ(200px); } #box img:nth-child(3) { -webkit-transform: rotateX(90deg) translateZ(200px); } #box img:nth-child(4) { -webkit-transform: rotateX(-90deg) translateZ(200px); } #box img:nth-child(5) { -webkit-transform: rotateY(-90deg) translateZ(200px); } #box img:nth-child(6) { -webkit-transform: rotateY(90deg) translateZ(700px); }
好了,下面是我们要做的事情。第一副图像完全不旋转,但是它将会在z轴上朝观看者靠拢200个像素。
第二副图像沿x轴旋转180度,使它远离观看者。然后它将在z轴上远离观看者200像素。
“请注意转换的顺序很要紧-旋转改变物体的基点然后沿着新的轴进行转化。”
我们第三和第四幅图分别沿x轴向下和向上旋转。它们都将沿新的z轴方向转换200个像素。
记住,我们的盒子是900像素宽、400像素高和400像素高。940像素*400像素的四面都互相隔着400像素。这就是为什么我们将它们都朝相反的方向转换200个像素的原因。我们将会将400像素*400像素的两端相对的转换900个像素。
第五和第六幅图现在在盒子的左侧,并不在中间。因此,我们第五和第六幅图将采用不同的转换。第五幅图将要沿y轴旋转负90度来面朝左侧,然后沿新的z轴转换200像素。这将把它放置在3D物体的左侧。第六幅图沿y轴旋转90度来 右侧,然后沿新的z轴转换700像素。这将把它放置在3D物体的右侧。
对于查看我们已完成效果的最佳方式就是查看当前图像的排列。如果你在Safari里预览幻灯片你将看到如下效果:
让我们隐藏前面的一面-当其他图像的位置都正确后我们再恢复它的显示。
#box img:nth-child(1) { -webkit-transform: rotateX(0deg) translateZ(200px); display: none; /* temporarily hide */ }
现在我们可以看到盒子的内部。
现在,移除我们第一副图像上的display:none。你将会发现盒子和它原来的大小相比靠观看者越近的部分看起来越大。最前面的一面看起来尤其的巨大和伸长。
要纠正这个问题我们必须要将整个3D物体超观看者相反的方向移动200像素。为box的样式添加-webkit-transform: translateZ(-200px)。当我们在它之上时还需要添加transition属性。
#box { position: relative; display: block; width: 900px; height: 400px; -webkit-transform: translateZ(-200px); /* Pushes 3D object back into place */ -webkit-transition: -webkit-transform 1s; /* Enables transitions for transforms */ }
完成这些设置后,我们将要开始让我们的盒子动起来。
第四步:动画
粘贴我们样式的最后一段。它将添加动画效果,我将在下面解释更多细节。
#fig1:focus #box { -webkit-transform: translateZ(-200px) rotateY(0deg); } #fig2:focus #box { -webkit-transform: translateZ(-200px) rotateX(-180deg); } #fig3:focus #box { -webkit-transform: translateZ(-200px) rotateX(-90deg); } #fig4:focus #box { -webkit-transform: translateZ(-200px) rotateX(90deg); } #fig5:focus #box { -webkit-transform: translateZ(-450px) rotateY(90deg); } #fig6:focus #box { -webkit-transform: translateZ(-450px) rotateY(-90deg); }
当我们 <figure>元素的每一面接收伪类:focus,我们旋转box以显示对应的那一面。注意box的旋转都与在每一面上使用的旋转相反。例如,第四幅图像沿x轴旋转负90度,要达到这样的效果,我们必须要将整个3D物体沿x轴旋转90度。这个转换确保3D物体我们将要看到的那一面总是沿着正确的距离离去。
这就是它了!在Safari里查看幻灯片,保证一切工作正常。
最后的CSS
最后style.css里的样式看起来会是这样:
/* RESET */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } :focus { outline: 0; } /* HTML5 tags */ header, section, footer, aside, nav, article { display: block; } html { width: 100%; height: 100%; background-color: #FFFFFF; background-image: -moz-linear-gradient(top, #FFFFFF, #b3b3b3); background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #FFFFFF),color-stop(1, #b3b3b3)); filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#b3b3b3'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#b3b3b3')"; } #container { width: 960px; margin: 0 auto; } #slideshow { width: 900px; margin: 50px auto 0 auto; padding: 50px 0 0 0; -webkit-perspective: 800; /* triggers a 3D space */ } figure { display: inline; -webkit-transform-style: preserve-3d; /* maintains 3D space */ } #box { position: relative; display: block; width: 900px; height: 400px; -webkit-transform: translateZ(-200px); /* Pushes 3D object back into place */ -webkit-transition: -webkit-transform 1s; /* Enables transitions for transforms */ } #box img { position: absolute; top: 0; left: 0; } figcaption { display: inline-block; width: 70px; height: 35px; background: rgba(0,0,0,0.6); border: 1px solid rgba(0,0,0,0.7); -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; text-align: center; line-height: 35px; color: #ffffff; text-shadow: 1px 1px 1px #000000; cursor: pointer; position: relative; top: -50px; left: 150px; margin: 0 30px 0 0; -moz-transition: all 0.1s linear; -o-transition: all 0.1s linear; -webkit-transition: all 0.1s linear; transition: all 0.1s linear; } figcaption:hover { background: rgba(0,0,0,0.8); } #box img:nth-child(1) { -webkit-transform: rotateX(0deg) translateZ(200px); } #box img:nth-child(2) { -webkit-transform: rotateX(180deg) translateZ(200px); } #box img:nth-child(3) { -webkit-transform: rotateX(90deg) translateZ(200px); } #box img:nth-child(4) { -webkit-transform: rotateX(-90deg) translateZ(200px); } #box img:nth-child(5) { -webkit-transform: rotateY(-90deg) translateZ(200px); } #box img:nth-child(6) { -webkit-transform: rotateY(90deg) translateZ(700px); } #fig1:focus #box { -webkit-transform: translateZ(-200px) rotateY(0deg); } #fig2:focus #box { -webkit-transform: translateZ(-200px) rotateX(-180deg); } #fig3:focus #box { -webkit-transform: translateZ(-200px) rotateX(-90deg); } #fig4:focus #box { -webkit-transform: translateZ(-200px) rotateX(90deg); } #fig5:focus #box { -webkit-transform: translateZ(-450px) rotateY(90deg); } #fig6:focus #box { -webkit-transform: translateZ(-450px) rotateY(-90deg); }
最后的思考
可能没有方法证明使用许多嵌套的<figure>和<figcaption>元素作为按钮是当前CSS3的推荐方式。这个试验也并没考虑到HTML内容、CSS样式和JS行为的区别。既然这些转换现在只能在Safari中表示,这个幻灯片并没有可能在客户端的项目中应用。但是这个试验的意义在于展示和推动HTML5和CSS3新特性的应用。
如果你对于让这个幻灯片支持更多的浏览器感兴趣,这里有一些有益的提示:
我希望朋友们喜欢这个教程。我渴望你们的回复,感谢你们阅读本文!