原文:http://net.tutsplus.com/tutorials/html-css-techniques/build-a-kickbutt-css-only-3d-slideshow/
作者:Will Moyer
译者:蒋宇捷(http://blog.csdn.net/hfahe)
友情提示:本文难度为中等,阅读完需要45分钟,理解需要一定的基础。
![](https://box.kancloud.cn/2016-08-02_57a05bd7178f0.gif)
![](https://box.kancloud.cn/2016-08-02_57a05bd73771a.gif)
[**下载**源文件](http://nettuts.s3.amazonaws.com/893_css3D/source_files/source_files.zip)
[**示例**在线观看**](http://nettuts.s3.amazonaws.com/893_css3D/source_files/index.html)**
译者注:观看示例请使用最新版的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最近撰写的[快速](http://net.tutsplus.com/tutorials/html-css-techniques/quick-tip-mimic-a-click-event-with-css/)[技巧](http://net.tutsplus.com/tutorials/html-css-techniques/quick-tip-mimic-a-click-event-with-css/)一文,描述了一种使用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](http://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看起来像是这样。
![](https://box.kancloud.cn/2016-08-02_57a05bd76d028.gif)
让我们为 <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);}
~~~
我们定义好的按钮看起来像如下一样:
![](https://box.kancloud.cn/2016-08-02_57a05bd784b21.gif)
**第三步:**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个像素。
![](https://box.kancloud.cn/2016-08-02_57a05bd79b774.gif)
第二副图像沿x轴旋转180度,使它远离观看者。然后它将在z轴上远离观看者200像素。
![](https://box.kancloud.cn/2016-08-02_57a05bd7b2ad0.gif)
“请注意转换的顺序很要紧-旋转改变物体的基点然后沿着新的轴进行转化。”
我们第三和第四幅图分别沿x轴向下和向上旋转。它们都将沿新的z轴方向转换200个像素。
![](https://box.kancloud.cn/2016-08-02_57a05bd7ca609.gif)
![](https://box.kancloud.cn/2016-08-02_57a05bd7e22c3.gif)
记住,我们的盒子是900像素宽、400像素高和400像素高。940像素*400像素的四面都互相隔着400像素。这就是为什么我们将它们都朝相反的方向转换200个像素的原因。我们将会将400像素*400像素的两端相对的转换900个像素。
第五和第六幅图现在在盒子的左侧,并不在中间。因此,我们第五和第六幅图将采用不同的转换。第五幅图将要沿y轴旋转负90度来面朝左侧,然后沿新的z轴转换200像素。这将把它放置在3D物体的左侧。第六幅图沿y轴旋转90度来右侧,然后沿新的z轴转换700像素。这将把它放置在3D物体的右侧。
![](https://box.kancloud.cn/2016-08-02_57a05bd804328.gif)
![](https://box.kancloud.cn/2016-08-02_57a05bd8246f7.gif)
对于查看我们已完成效果的最佳方式就是查看当前图像的排列。如果你在Safari里预览幻灯片你将看到如下效果:
![](https://box.kancloud.cn/2016-08-02_57a05bd847864.gif)
让我们隐藏前面的一面-当其他图像的位置都正确后我们再恢复它的显示。
~~~
#box img:nth-child(1) { -webkit-transform: rotateX(0deg) translateZ(200px); display: none; /* temporarily hide */}
~~~
现在我们可以看到盒子的内部。
![](https://box.kancloud.cn/2016-08-02_57a05bd85dd7d.gif)
现在,移除我们第一副图像上的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里查看幻灯片,保证一切工作正常。
![](https://box.kancloud.cn/2016-08-02_57a05bd87b96e.gif)
**最后的**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新特性的应用。
如果你对于让这个幻灯片支持更多的浏览器感兴趣,这里有一些有益的提示:
- 使用Modernizr(Modernizr 是一个利用 JS 和 CSS 来检测浏览器所支持功能的小工具)。我是认真的。
- 只有Safari支持3D转换,但是你可以使用2D转换创建一个支持更多浏览器的酷炫幻灯。
- Opacity透明度属性可以创建一个强大的淡入淡出幻灯,几乎支持全部的浏览器(在IE上可以使用filter)。
- 绝对定位的<figcaption>按钮在Firefox下会产生截断。我知道这非常神奇。确保你使用的是相对定位。
我希望朋友们喜欢这个教程。我渴望你们的回复,感谢你们阅读本文!
- 前言
- AutoPager的简单实现
- 利用CSS3特性巧妙实现漂亮的DIV箭头
- IE9在Win7下任务栏新特性简介
- 浏览器九宫格的简单实现
- Raphael js库简介
- 使用CSS3构建Ajax加载动画
- 用CSS3创建动画价格表
- 用CSS3实现浏览器的缩放功能
- 用纯CSS3实现QQ LOGO
- 用CSS3创建旋转载入器
- 使用Javascript开发移动应用程序
- 用HTML5创建超酷图像灰度渐变效果
- 使用CSS3创建文字颜色渐变(CSS3 Text Gradient)
- 仅用CSS创建立体旋转幻灯片
- 如何创建跨浏览器的HTML5表单
- 用CSS3实现动画进度条
- HTML5 Guitar Tab Player
- 奇妙的HTML5 Canvas动画实例
- 谈HTML5和CSS3的国际化支持
- 实现跨浏览器的HTML5占位符
- 前端开发必备工具:WhatFont Bookmarklet-方便的查询网页上的字体
- 使用HTML5和CSS3来创建幻灯片
- HTML5之美
- 如何使用HTML5创建在线精美简历
- 以小见大、由浅入深-谈如何面试Javascript工程师
- 快速入门:HTML5强大的Details元素
- 用CSS3实现图像风格
- HTML5视频字幕与WebVTT
- 用纯CSS3实现Path华丽动画
- 用3个步骤实现响应式网页设计
- 遇见CSS3滤镜
- 关于CSS3滤镜的碎念
- 用纯CSS3绘制萌系漫画人物动态头像
- CSS3新的鼠标样式介绍
- 用HTML5献上爱的3D玫瑰
- 对HTML5 Device API相关规范的解惑
- 如何使用HTML5实现拍照上传应用
- 2012第一季度国外HTML5移动开发趋势
- HTML5新特性:范围样式
- 百度开发者大会-《用HTML5新特性开发移动App》PPT分享
- Chrome 19对于HTML5最新支持的动态:电池状态API,全屏API,震动API,语音API
- 遇见Javascript类型数组(Typed Array)
- 用HTML5 Audio API开发游戏音乐
- 用HTML5实现人脸识别
- 用Javascript实现人脸美容
- Chrome 20对于HTML5最新支持的动态:颜色输入,网络信息API,CSS着色器
- 用HTML5实现手机摇一摇的功能
- 用HTML5实现iPad应用无限平滑滚动
- 用非响应式设计构建跨端Web App
- 了解SVG
- HTML5图像适配介绍
- HTML5安全:内容安全策略(CSP)简介
- HTML5安全:CORS(跨域资源共享)简介
- 用CSS3 Region和3D变换实现书籍翻页效果
- 谈谈移动App的思维误区
- Chrome新特性:文件夹拖拽支持
- 《关注HTML5安全》
- HTML5安全风险详析之一:CORS攻击
- HTML5安全风险详析之二:Web Storage攻击
- HTML5图像适配最新进展:响应式图片规范草案
- HTML5移动Web App相关标准状态及路线图
- HTML5安全风险详析之三:WebSQL攻击
- Chrome引入WebRTC支持视频聊天App
- HTML5安全风险详析之四:Web Worker攻击
- HTML5安全风险详析之五:劫持攻击
- HTML5安全风险详析之六:API攻击
- HTML5安全攻防详析之七:新标签攻击
- 在iOS Safari中播放离线音频
- 使用WebRTC实现远程屏幕共享
- Firefox、Android、iOS遇见WebRTC
- HTML5光线传感器简介
- HTML5安全攻防详析之八:Web Socket攻击
- HTML5安全攻防详析之完结篇:HTML5对安全的改进
- 激动人心!在网页上通过语音输入文字 - HTML5 Web Speech API介绍
- Web滚动性能优化实战
- 用CSS3设计响应式导航菜单
- 用HTML5构建高性能视差网站
- 漫谈@supports与CSS3条件规则
- HTML5下载属性简介
- 如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(一)
- 如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(二)
- 趋势:Chrome为打包应用提供强大新特性
- 从HTML5移动应用现状谈发展趋势
- 基于HTML5的Web跨设备超声波通信方案