译自:http://net.tutsplus.com/tutorials/html-css-techniques/how-to-create-presentation-slides-with-html-and-css-2/
译者:蒋宇捷(转载请标明出处-http://blog.csdn.net/hfahe)
下载源文件 示例(用向左向右键翻页,Ctrl加+或者-键放大缩小)
我曾经尝试过许多种软件来创建幻灯片,但是为什么不使用我们已经熟悉的工具,而是去学习另外一种程序?我们可以轻松的使用HTML和CSS来创建漂亮的幻灯片。我下面将向你展示实现的方法。
0-目录结构
在我们开始前,让我们来创建相当简单的目录结构。我们将需要以下文件:
· index.html
· css/style.css
· js/scripts.js
· img/
· slides/
一个简单的基本模版。Slides目录目前为空,我们稍后将填充它。
1-编写HTML
让我们开始为幻灯片页面创建基本的HTML页面。将下面的代码粘贴到index.html文件里。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <link href="style.css" rel="stylesheet" /> <title>My Great Presentation</title> </head> <body> <div class="wrap"> <div id="slides"> <!-- load in slides --> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script> </body> </html>
上面的代码需要一些精简,我们要感谢HTML5。例如script和link标签不再有type属性,更简洁的DOCTYPE,简单有趣的meta charset标签。
2-幻灯片
Load()方法是一个从服务器载入数据的AJAX方法,并在选定的元素中插入返回的HTML代码。
现在你可能觉得奇怪我们如何处理每一条幻灯片。我们这里有多种选择方式。我们可以用div包裹每一张幻灯片,并且在#slides容器里放置一大段的HTML代码。我的直觉告诉我这种方式会使得每一个独立的幻灯片的编辑过程更为耗时,因为我们随后必须要从幻灯片所有的标记里查找我们所需的。在这个教程里我们采用替代方案,我选择将每一个幻灯片放在单独的.html文件里。我们稍候可以使用jQuery的load()方法来加载每一张幻灯片,并将它们添加到容器里。
创建一系列有编号的HTML文件,并且将它们放在slides目录里,就像如下所示:
· slides/
o 0.html
o 1.html
o 2.html
o 3.html
o 4.html
在每一个这样的文件中,我们将为我们所需的幻灯片插入HTML标记。作为示例,让我们创建一个“关于我们”幻灯片。
1.html
<div> <h3> About Me</h3> <ul> <li> Nettuts+ Editor</li> <li> Envato Marketplaces Manager</li> <li>Wicked WordPress Themes</li> <li>Theme Tumblr Like a Pro</li> </ul> </div>
可以使用任何你想要的内容来编写这个文件。
3-加载幻灯片
在关注幻灯片的样式之前,我们需要使用jQuery将这些幻灯片载入到文档里。但是比起创建大量的变量和方法,我们将把所有的内容存储到一个名为Slides的变量里。
var Slides = { };
然后,载入这些幻灯片到文档的过程将被存储到一个名为loadContent()的方法里。让我们开始创建编写代码。
var Slides = { loadContent : function() { } }
要加载slides目录下的所有幻灯片,我们首先必须要知道要有多少个幻灯片。但是Javascript并没有访问文件系统的权限,所以我们在初始化对象前必须要传递进幻灯片的数量。
以此为前提,让我们创建init()方法来作为控制器。这个方法将会接受一个参数来制定幻灯片的总张数。这将会分配给Slides对象的一个属性。
var Slides = { totalSlides : '', init : function( totalSlides ) { // If nothing was passed to this function, we can't continue. if ( !totalSlides ) throw new Error('Please pass the total number of slides to the init method'); Slides.totalSlides = totalSlides; // Load the slides Slides.loadContent(); }, loadContent : function() { } }
这非常好,但是除非我们调用init()方法,没有代码将会被执行。
var Slides = { totalSlides : '', init : function( totalSlides ) { // If nothing was passed to this function, we can't continue. if ( !totalSlides ) throw new Error("Please pass the total number of slides to the init method"); Slides.totalSlides = totalSlides; // Load the slides Slides.loadContent(); }, loadContent : function() { } } // All right; let's do this. We'll assume that we've created 6 slides, total. Slides.init( 6 );
4-三种加载幻灯片的方法
让我们开始加载幻灯片的第一步,我们稍后将逐步改进代码。
loadContent : function() { for ( var i = 0; i < Slides.totalSlides; i++ ) { $('<div id="#slide-' + i + '"></div>') .load('slides/' + i + '.html') .appendTo( $('#slides') ); } }
在上面,我们为指定的所有幻灯片创建了一个新的div元素。每个div会有一个名为slide-n的id。在创建每个元素后,我们载入slides文件夹下存储的幻灯片内容。一旦这些HTML片段从服务器获得,我们将新创建的div添加到slides容器中。
我们可以做得更好
这些代码确实能够工作,但是我们可以做得更好。以上代码有如下问题:
· 遍历:对于每个幻灯片,我们遍历slides元素的DOM节点。这是没有必要而且造成了浪费。同时,一旦我们在项目中一直使用slides容器节点,有理由将它存储为我们slides对象的一个属性。我们立即将这么来做。
· 重绘:以上代码将造成很多页面重绘,这将增加页面的加载时间。比起多次调用appendTo()方法(在我们的例子中是6次),让我们限制重绘为一次。
遍历
让我们先修复遍历的问题。
var Slides = { totalSlides : '', container : $( "#slides" ), init() { ... }, loadContent() { ... } }
采用这种方式我们可以一次性的在slides元素中查找出文档。
如果你还对这么做的优点心存疑虑,可以把它想象成跳到一个池子中,来寻找一个硬币。每次你调用$('#slides')时,Javascript引擎会进入变量池来一次又一次的寻找这个硬币。但是,如果我们换成将$('#slides')存储在一个变量里,Javascript引擎将不必用到变量池。它将会记住硬币在哪儿。
重绘
现在,我们开始考虑讨厌的重绘问题。有两种方法来限制页面重绘,我们将都会进行尝试。
文档片段
Javascript文档片段允许我们存储HTML块。比起我们之前多次更改DOM树的做法,我们只需调用appendTo()方法一次。
这里有文档片段更多的相关信息。
loadContent : function() { var frag = document.createDocumentFragment(), bit; for ( var i = 0; i < Slides.totalSlides; i++ ) { bit = $('<div id="#slide-' + i + '">'</div>') .load('slides/' + i + '.html')[0]; frag.appendChild(bit); } Slides.container.append(frag); }
记住我们不再在for循环里调用appendTo()方法。取而代之的是只调用了它一次。唯一需要注意到的是在我们调用load()方法之后[0]写法。我们用它的目的何在?
我们需要的是HTML元素,所以需要使用[0]或者get()方法来从jQuery方法获得。
隐藏容器
我们第二个选择是隐藏容器元素。当我们这么做时,不管你在这个元素里添加了多少次新的元素,都不会导致页面重绘。这将会是你工具箱里常用的小技巧。
loadContent : function() { // Hide the container. Slides.container.hide(); for ( var i = 0; i < Slides.totalSlides; i++ ) { $(''<div id="#slide-' + i + '">'</div>') .load('slides/' + i + '.html') .appendTo(Slides.container); } // Now display the slides container again - causing exactly one reflow. Slides.container.show(); }
所以任意一个方法都可以改善这个问题。选择任意一个你喜欢的。
如果你现在在浏览器查看我们的项目,假定你已经添加了一些虚拟的幻灯片到slides文件夹,你将会沿着线条看到一些内容:
如果我们使用Firebug或者Chrome的开发者工具查看,可以像预期一样看到,幻灯片已经插入到slides div容器里。
5-让它更美
我们下一步将替换样式表。我们将同时关注美感和功能两个方面。要让每个幻灯片从左到右进行转换,我们将要灵巧的处理样式:
我们将开始创建画布。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <link href="style.css" rel="stylesheet" /> <title>My Great Presentation</title> </head> <body> <div class="wrap"> <div id="slides"> <!-- load in slides --> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script> </body> </html>
我们的容器是一个类名为wrap的div。我们将要为它提供1180像素的宽度并放置在页面中央。
.wrap { margin: auto; width: 1180px; overflow: hidden; /* because children will be floated */ }
然后,因为每一个幻灯片必须水平的切换,我们必须使得slides div尽可能的宽。
#slides { width: 999999px; }
现在是有趣而小小可怕的部分。想象一个传统的幻灯片,内容是不是通常水平和上下居中的?正是如此。因为我们有工程100%的控制权,所以不需要担心浏览器的一致性。因为幻灯片是需要我们自己来展示的,所以我们可以自由使用自己所喜爱的浏览器。这种方式下,我们可以使用很多浏览器中并不支持的新特性,例如弹性盒子模型。
我们来开始指定每个幻灯片的尺寸,浮动每张幻灯片,一些逼真的空间(margins)。
#slides > div { height: 600px; width: 1180px; float: left; margin-right: 200px; text-align: center; }
但是记住,文字必须垂直居中。弹性盒子模型是我们的救星。
#slides > div { height: 600px; width: 1180px; float: left; margin-right: 200px; text-align: center; /* Flexible Box Model */ display: -webkit-box; -webkit-box-align: center; -webkit-box-orient: horizontal; -webkit-box-pack: center; display: box; box-align: center; box-orient: horizontal; box-pack: center; }
然后,我们要为幻灯片添加一个漂亮的径向渐变。说实话,CSS径向渐变让我非常困惑,我几乎记不住它的格式。就这点而言,我通常为渐变创建笔记,或者使用网上一些不同的渐变生成器。
body { background-image: -webkit-gradient( radial, 50% 50%, 0, 50% 50%, 1000, from(rgba(245,245,245,1)), to(rgba(100,100,100,1)) ); }
同时我们在适当的位置有基本的结构。此时我鼓励你为头部添加样式,也许是创建一个最小的格子,和其他你能想到的一切。
#slides h1, #slides h2, #slides h3, #slides h4, #slides h5 { color: #292929; font-family: 'League Gothic', sans-serif; letter-spacing: -5px; margin-top: 0; text-shadow: 5px 3px 0 white; } #slides > div h2 { font-size: 180px; line-height: 1em; margin: 0; }
令人惊奇的是我们在调整字符间距和添加一些灵巧的字符阴影时能够达到的效果。现在看起来好多了。
6-下一张幻灯片
下一个步骤是处理幻灯片间切换的过程。自然的,因为没有空间来放置按钮,我们可以监听键盘上的左右键按下事件。我们将把这个功能存储在slides对象一个名为keyPress的新方法。
var Slides = { ... init : function() { ... }, loadContent: function() { ... }, keyPress : function() { $(document.body).keydown(function(e) { // if left or right arrow key is pressed if ( e.keyCode === 39 || e.keyCode === 37 ) { e.preventDefault(); ( e.keyCode === 39 ) ? Slides.next() : Slides.prev(); } }); } }
jQuery提供了工具性的keydown方法,用于绑定需要的事件监听。这代表传入的回调方法将会在每个键按下时被执行。然而,我们只对向左和向右键感兴趣,它们的键值分别是39和37。如果其中一个键被按下,我们首先阻止这个键的默认行为,然后调用next()或者prev()方法来切换幻灯片。
下一张幻灯片
现在让我们开始编写next()方法。当这个方法被调用时,它需要执行一些操作:
· 更新URL里的hash值,采用这种方法,我们可以轻松的为指定的幻灯片传送地址。
· 将当前的幻灯片进行向左的动画切换,并显示下一张幻灯片。
但是继续之前,我们如何知道幻灯片转换时需要移动多少宽度?这应该是slides容器的宽度,但是我们不想把这个硬编码到代码里,而且也不需要。这是因为,如果稍后想要改变画布的大小,我们还需要进入Javascript文件里并且更新尺寸大小。作为替代,让我们动态的判断容器的宽度和margin。
让我们在slides对象里添加一个名为slideWidth的新属性。然而,我们将不能决定幻灯片的宽度,直到它们已经通过loadContent方法插入到DOM树中。
var Slides = { ... // New property stores the width of each slide slideWidth : '', ... init : function( totalSlides ) { ... }, loadContent : function() { ... }, // Determine the width of the slide... setSlideWidth : function() { var each = Slides.container.children( 'div' ); Slides.slideWidth = each.width() + ( parseInt( each.css('margin-right'), 10 ) ); } }
哎呀,这一行看起来有一点可怕!
Slides.slideWidth = each.width() + ( parseInt( each.css('margin-right'), 10 ) );
但是不要担心,这相当的简单。我们将要改变slides.slideWidth属性并让它等于幻灯片的宽度加上右边的margin。因为获取幻灯片的margin-right属性会返回像素值,我们需要将它们切分开,并使用parseInt方法获得数值。
为了让计算的需求更清晰,假定右侧的margin值等于200像素。
console.log ( typeof each.css('margin-right').split('px')[0] ); // value is 200. Typeof is still string, not integer.
同时通过这种方式,我们将要动态的决定幻灯片的宽度。回到next()方法,我们需要一直跟踪幻灯片的位置。这样当幻灯片从第四张换到第五张时,我们可以清楚的知道需要转换多少宽度。我们将把这个值存储在一个新的属性translateAmount中。
translateAmount : '', next : function() { Slides.translateAmount -= Slides.slideWidth; }
让我们分开来解释。当第一次按下向右键,我们设置translateAmount属性等于slideWidth,在我们的例子中是1380像素。如果我们再次按下向右键,这个值将会更改为2760像素。
更新Hash值
使用这个next方法,我们还可以更改url里的hash值,例如先是形如example.com/index.html#slide-1,然后更新为example.com/index.html#slide-2。要这样做的话,我们必须要跟踪读者正在阅读的幻灯片。
currentSlide : 0, ... next : function() { Slides.translateAmount -= Slides.slideWidth; Slides.updateHash( ++Slides.currentSlide ); }, updateHash : function() { location.hash = '#slide-' + Slides.currentSlide; }
注意我们现在在将currentSlide在传入updateHash方法前加1。这是合适的,当我们按下向右键,hash值将会更新为新幻灯片的值。
幻灯片动画
最后,在已经设置了所有必须的值后,我们可以来设置幻灯片动画了。
next : function() { Slides.translateAmount -= Slides.slideWidth; Slides.updateHash( ++Slides.currentSlide ); Slides.animate(); }, animate : function() { Slides.container .children() .css( '-webkit-transform', 'translateX(' + Slides.translateAmount + 'px)'); }
为了更好的性能,我们将使用CSS3的特性来进行幻灯片的切换。我们必须要更新CSS文件。
#slides div { ... -webkit-transition: all 1s linear; transition: all 1s linear; }
前一张幻灯片
Prev方法和next非常类似。
prev : function() { // No more left to go back. if ( Slides.translateAmount === 0 ) return; Slides.translateAmount += Slides.slideWidth; Slides.updateHash( --Slides.currentSlide ); Slides.animate(); }
现在,在我们转换到幻灯片开始时,我们必须要反转translateAmount变量和hash值。另外,我们必须要考虑用户在第一张幻灯片时按下向左键时的情况。而当这种情况出现时,我们什么都不必做。
最后的Javascript脚本
var Slides = { container : $('#slides'), totalSlides : '', translateAmount : 0, currentSlide : 0, slideWidth : '', init : function(totalSlides) { var each; if ( !totalSlides ) throw new Error('Please pass the total number of slides.'); Slides.totalSlides = totalSlides; Slides.loadContent(); each = Slides.container.children('div'); // Determine the width of our canvas Slides.slideWidth = each.width() + ( parseInt( each.css('margin-right'), 10 ) ); Slides.keyPress(); }, loadContent : function() { Slides.container.hide(); for ( var i = 0; i < Slides.totalSlides; i++ ) { $('<div id="#slide-' + i + '"></div>') .load('slides/' + i + '.html') .appendTo(Slides.container); } Slides.container.show(); }, keyPress : function() { $(document.body).keydown(function(e) { // if left or right arrow key is pressed if ( e.keyCode === 39 || e.keyCode === 37 ) { e.preventDefault(); ( e.keyCode === 39 ) ? Slides.next() : Slides.prev(); } }); }, next : function( ) { Slides.translateAmount -= Slides.slideWidth; Slides.updateHash( ++Slides.currentSlide ); Slides.animate(); }, prev : function() { // No more left to go back. if ( Slides.translateAmount === 0 ) return; Slides.translateAmount += Slides.slideWidth; Slides.updateHash( --Slides.currentSlide ); Slides.animate(); }, animate : function() { Slides .container .children() .css( '-webkit-transform', 'translateX(' + Slides.translateAmount + 'px)' ); }, updateHash : function( direction ) { // Update current Slides and hash. location.hash = '#slide-' + Slides.currentSlide; } }; // All right; let's do this. Slides.init(6);
完成
所有的工作完成了。这并不困难。重要的地方在于,如果你在一个低或者高分辨率的情况下来观看幻灯片,你可以通过Ctrl加+或者-键来进行页面的缩放。如果你有任何的问题或者建议请让我知道,谢谢。