译者:为之漫笔
“我就想不用jQuery实现简单的JavaScript幻灯片”
这里所说的幻灯片,或者叫图片传送带、图片滑块、旋转图等等,是JavaScript学习者必修课之一。
本教程内容如下:
- 不用jQuery等外部库实现简单的幻灯片
- 理解UX和无障碍问题,包括是否该用幻灯片
- 给幻灯片添加控件
不依赖库实现幻灯片的主要好处是页面速度会变快,因为代码少了。而且,随便用到哪里都不用担心加载外部文件的问题。
读者最好懂JavaScript,包括函数、事件、样式过渡。另外推荐大家看看我的这个尽可能只用JavaScript做一些实用的东西都要学什么的路线图。
做个简单的幻灯片
HTML代码
HTML需要有个容器,容器里是幻灯片:
<ul id=""slides"">
<li class=""slide showing"">Slide 1</li>
<li class=""slide"">Slide 2</li>
<li class=""slide"">Slide 3</li>
<li class=""slide"">Slide 4</li>
<li class=""slide"">Slide 5</li>
</ul>
CSS
CSS要做下面几件事:
- 确定幻灯片的容器
- 在容器里将幻灯片堆叠起来
- 确定幻灯片长啥样以及何时显示或隐藏
- 实现淡入淡出效果
看CSS前,请注意不要使用与你的网页可能冲突的类或ID。本文使用了简短的名字。
CSS在这儿:
/*
基本样式:
支撑幻灯片
*/
#slides {
position: relative;
height: 300px;
padding: 0px;
margin: 0px;
list-style-type: none;
}
.slide {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
opacity: 0;
z-index: 1;
-webkit-transition: opacity 1s;
-moz-transition: opacity 1s;
-o-transition: opacity 1s;
transition: opacity 1s;
}
.showing {
opacity: 1;
z-index: 2;
}
再添加一些装饰性的幻灯片样式,以下是示例:
/*
非基本样式:
想要什么样,你自己定
*/
.slide {
font-size: 40px;
padding: 40px;
box-sizing: border-box;
background: #333;
color: #fff;
}
.slide:nth-of-type(1) {
background: red;
}
.slide:nth-of-type(2) {
background: orange;
}
.slide:nth-of-type(3) {
background: green;
}
.slide:nth-of-type(4) {
background: blue;
}
.slide:nth-of-type(5) {
background: purple;
}
JavaScript
JavaScript做一件事:隐藏当前幻灯片,显示下一张。为此,只需改变相关幻灯片的类名。
JavaScript代码:
var slides = document.querySelectorAll('#slides .slide');
var currentSlide = 0;
var slideInterval = setInterval(nextSlide,2000);
function nextSlide() {
slides[currentSlide].className = 'slide';
currentSlide = (currentSlide+1)%slides.length;
slides[currentSlide].className = 'slide showing';
}
下面分析一下。
- 先用
querySelectorAll拿到容器中的幻灯片 - 然后声明一个变量保存当前幻灯片
- 最后通过定时器每2秒(2000毫秒)切换一次幻灯片
重点看看nextSlide函数。
- 首先,把当前幻灯片的类置为不可见(去掉
showing),CSS过渡会自动实现淡出。 - 然后给当前幻灯片加1,这里使用
%运算实现到最后一张后自动归零,即回到第一张;%运算符执行两个数相除,然后取得余数。 这个运算特别适合计算时间、日历等需要循环归零的情景。我们这个例子有5张幻灯片,那么依次执行取余运算的过程就是:1%5=1, 2%5=2, 3%5=3, 4%5=4, and 5%5=0。 - 得到当前幻灯片编号之后,再给它的类加上
showing。同样,CSS不透明度的渐变会自动出现。
祝贺你,一个简单的幻灯片诞生了。
注意兼容性
CSS过渡在IE9及以下版本是不能用的,在这些浏览器里,幻灯片会简单地切换到下一张。
这个简单的幻灯片是什么效果呢,看这里:Basic JavaScript Slideshow without jQuery 。
用户体验与无障碍
使用幻灯片之前,先要好好想想为什么在网页里用它。如果不小心的话,幻灯片很可能给你的网页带来用户体验和无障碍方面的问题。
幻灯片可能隐藏重要内容
如果是非常重要的内容,不应该放在幻灯片里。不能指望所有人都能使用合适的浏览器,这还不算无障碍问题。
根据 美国圣母大学的一项研究,只有1.07%的人会点击幻灯片中最突出的一张图,3%甚至更少的人会点击第一张之后的其他幻灯片。这说明通过幻灯片传达重要内容有多危险。
用户可能分不清你的网站是干什么的
如果幻灯片做得非常大,那么这真是个问题。如果你都不知道向用户展示什么,还怎么指望用户做出你期望的决定? (原推文)
网站应该明确告诉用户自己需要他们干什么,如果幻灯片妨碍了你达成这个目标,那该好好反思一下。
转换率优化公司WiderFunnel曾对幻灯片的有效性做过测试,并得出如下结论:
我们多次测试了轮播图,发现通过它展示主页内容效果很差;
有空的话,真的建议读一读他们这篇文章 。
移动用户可能不会高兴
幻灯片会导致加载时间过长,造成界面卡顿。
什么情况下可以使用幻灯片
既然幻灯片有这么多问题,那么什么情况下可以用它呢?下面是我的一些建议。
给人一个大体的印象
如果你不在乎用户是否会注意到某张幻灯片,只是想传达一种大概的印象,可以用。这种情况下,只要用户看到一张幻灯片,目的就达到了。
幻灯片外的主要内容很容易找到
比如,可能你想通过幻灯片展示某个景点、博物馆、会议或某系列产品的图片,但网站的其他地方也准备了相应图库或产品图片的完整展示区。这时候用幻灯片还是不错的。
在渐进增强的情况下
这种情况更普遍,前提是不要因为这个非网站主要功能的装饰带来太多问题。只要它只是装饰不是障碍就好。
无障碍指南
如果幻灯片的内容比较重要,应该做无障碍处理。当然,应该首先考虑到底该不该用幻灯片。
如果你(或你的客户)坚持要用,这是一篇关于幻灯片无障碍化的文章。
根据这篇文章
幻灯片要做到无障碍,必须有五个条件:
允许用户停止全部切换
为键盘、鼠标和触摸设备提供无障碍访问机制
为幻灯片提供有效、可理念的焦点顺序指示
有效的代码和样式
为幻灯片提供有意义的替换
此外,这篇文章有一位评论者给出了是否决定使用幻灯片的有用资源。
为了让幻灯片无障碍,下面我们就来添加一些控件。
为幻灯片添加控件
我们要添加“暂停/播放”、“下一张”和“上一张”按钮。
暂停/播放
首先为按钮添加HTML:
<button class=""controls"" id=""pause"">Pause</button>
接下来写JavaScript:
var playing = true;
var pauseButton = document.getElementById('pause');
function pauseSlideshow() {
pauseButton.innerHTML = 'Play';
playing = false;
clearInterval(slideInterval);
}
function playSlideshow() {
pauseButton.innerHTML = 'Pause';
playing = true;
slideInterval = setInterval(nextSlide,2000);
}
pauseButton.onclick = function() {
if(playing) {
pauseSlideshow();
} else {
playSlideshow();
}
};
以上脚本都做什么了?
playing变量保存着幻灯片是否在播放的状态- 接着把暂停按钮也保存到一个变量中
pauseSlideshow函数负责暂停幻灯片,并把“暂停”改成“播放”playSlideshow相反- 最后,为暂停/播放按钮添加一个单击处理程序,用于切换暂停和播放
加了这个按钮后的效果怎么样?看这里:JavaScript Slideshow With Pause Button 。
下一张和上一张
还是先添加HTML:
<button class=""controls"" id=""previous"">Previous</button>
<button class=""controls"" id=""next"">Next</button>
JavaScript,把
function nextSlide() {
slides[currentSlide].className = 'slide';
currentSlide = (currentSlide+1)%slides.length;
slides[currentSlide].className = 'slide showing';
}
改成:
function nextSlide() {
goToSlide(currentSlide+1);
}
function previousSlide() {
goToSlide(currentSlide-1);
}
function goToSlide(n) {
slides[currentSlide].className = 'slide';
currentSlide = (n+slides.length)%slides.length;
slides[currentSlide].className = 'slide showing';
}
为灵活起见,增加了goToSlide函数。同时,currentSlide变量的计算也做了一点改动,目的是防止出现负值。如果你想测试,可以给slides.length一个值,看看随着n变化currentSlide会怎么样。
下面添加JavaScript,让这个按钮在被点击时干它该干的事:
var next = document.getElementById('next');
var previous = document.getElementById('previous');
next.onclick = function() {
pauseSlideshow();
nextSlide();
};
previous.onclick = function() {
pauseSlideshow();
previousSlide();
};
控制添加好了。效果如何呢?看这里:JavaScript Slideshow With Controls 。
为用户提供了“下一张”和“上一张”按钮,用户就不会被自动播放“欺负”了。
因为这些控件就是HTML按钮,所以可以通过键盘来操控。
至于它们的样式和位置,随便你,只要明显,能用就行。
如果你还想加上用键盘上的左、右键控制,那么要保证用户在其他地方使用这两个键的时候关闭此处的控件。
防止没有JavaScript
偶尔会碰到JavaScript加载失败、被关闭,甚至设备不支持的情况。理想的情况当然是让用户仍然可以正常使用。如何做后备取决于你的目的。可以只展示第一张图片,也可以用一个列表展示所有图片。
如果幻灯片的主要目的只是给人一个大概的印象,那么显示保持网页布局不变比展示所有图片更重要。
如果确实需要展示所有图片,那你就把它们都罗列出来呗。
这两种情况,下面都会介绍。
无JavaScript时隐藏控件
默认使用CSS隐藏控制:
.controls {
display: none;
}
然后使用JavaScript显示控制。这样,用户会在有JavaScript的时候看到控件。
var controls = document.querySelectorAll('.controls');
for(var i=0; i<controls.length; i++){
controls[i].style.display = 'inline-block';
}
以上代码循环所有控制,把它们都显示出来。
无JavaScript时列出所有图片
首先把.slide类的CSS由position: absolute;改为position: static;。这样,默认就是列出所有幻灯片。
然后添加JavaScript循环每一张幻灯片并将它们的定位改为绝对,像下面这样(一定要把这些代码放在slides变量后面):
for(var i=0; i<slides.length; i++) {
slides[i].style.position = 'absolute';
}
这样,幻灯片在JavaScript可用时就不会列出来了。
小结一下
我们讲了怎么做一个简单的幻灯片,如果处理用户体验和无障碍问题,以及如何添加控件。
本文最重要的,是想让大家思考:到底什么时候该用幻灯片,如果你想在网页中放个什么东西,请先想一想会对用户造成什么影响,以及它对你实现目标有没有帮助。如果答案明确,再去做或不做。
你想到什么了?关于幻灯片你有没有自己的经验或教训?或者有好玩的故事?欢迎留言。