Developer

Build a carousel with JavaScript

Next time you are thinking about using Flash, perhaps you should consider Javascript to build a carousel.

Flash can be make Web sites look pretty but for one reason or another not everyone has the player installed on the client browser. If you or your users are one of those poor unfortunates that has a 64-bit linux distro or you just hate having animations on your Web page, then you are forced to go without flash.

In this article we'll show you how to build a more usable carousel in JavaScript instead of Flash.

JavaScript - The lesser of two evils

For the purpose of this article we're not going to debate why we are developing a carousel and accept that we are forced to make one.

Then the question becomes: why use JavaScript over Flash?

  • It is lighter than the Flash implementation - by optimising our code we will be able to have a functional carousel in only a couple of kilobytes, it will take longer for the images to load than our HTML and JavaScript.
  • Maintainability is another reason, plenty of developers know JavaScript compared to those that are competent in Flash. Perhaps there are not the design resources to create a fully featured flash implementation, suddenly leaving it to the developers means JavaScript is a viable alternate.
  • Degradation. It is far easy to deliver useful content to someone with JavaScript turned off than it is for someone without Flash.
  • Accessibility. It is easier for a screen reader to navigate a carousel that is inline than outside have it in a Flash object.
  • Google. If your content is in the page then Google can index it, if it is in Flash than the Googlebot cannot follow the links without hiding the carousel content in the page.

The HTML Base

With these reasons in mind, let's begin to create our carousel by showing purely the four stories we are going to use in this example.

<html>
<body>
<div id="storyContainer">
<div id="story1">
	<a href="http://www.builderau.com.au/program/iis/soa/Protect_IIS_log_files_by_moving_them_to_a_secure_location/0,339028427,339271617,00.htm" class="ched">Secure IIS</a>
	   Log files are essential to reconstruct events before an IIS Web server failure. Learn how to protect your log files with this tip.
	  <span class="fstory"><a href="http://www.cnet.com.au/software/security/0,39029558,40058242,00.htm">Full story</a></span>
</div>
<div id="story2">
	<a href="http://www.builderau.com.au/program/html/soa/Microformats_and_Mapping/0,339028420,339271486,00.htm" class="ched">User Group Mash</a>
	   Find an Aussie user group near you with our new Google maps interface.
	  <span class="fstory"><a href="http://www.builderau.com.au/program/html/soa/Microformats_and_Mapping/0,339028420,339271486,00.htm">Full story</a></span>
</div>
<div id="story3">
	<a href="http://www.builderau.com.au/program/dotnet/soa/Quick_Start_guide_to_Microsoft_NET_development/0,339028399,339271495,00.htm" class="ched">.NET 101</a>
	   Learn how the .NET Framework works and the tools you'll need to get up and running in this quick start guide.
	  <span class="fstory"><a href="http://www.builderau.com.au/program/dotnet/soa/Quick_Start_guide_to_Microsoft_NET_development/0,339028399,339271495,00.htm">Full story</a></span>
</div>
<div id="story4" >
	<a href="http://www.builderau.com.au/program/css/soa/Understanding_the_CSS_box_model/0,39028392,39269220,00.htm" class="ched">Understand CSS</a>
	   Before diving into CSS learn some of the core drivers and concepts.

	  <span class="fstory"><a href="http://www.builderau.com.au/program/css/soa/Understanding_the_CSS_box_model/0,39028392,39269220,00.htm">Full story</a></span>
</div>
</div>
</body>
</html>

The Mona Lisa has nothing on us at this point. Let's add some style to these divs and make it more like the carousels we know:


<html>
<head>
<style>
.storydiv {
    height:182px;
    width:355px;
    padding-left:175px;
    top:0px;
    left:0px;
}

#story1 {
    background:url(http://www.builderau.com.au/i/s/cov/securitychain170110.gif) no-repeat;
}

#story2 {
    background:url(http://www.builderau.com.au/i/s/cov/browser170110.jpg) no-repeat;
}

#story3 {
    background:url(http://www.builderau.com.au/i/s/cov/dotnet170110.gif) no-repeat;
}

#story4 {
    background:url(http://www.builderau.com.au/i/s/cov/tools170110.jpg) no-repeat;
}

.storyDesc{
    padding-top: 10px; 
    padding-right: 8px;
    display:block;
}

.fStory {
     padding-top: 10px;
     display:block;
     font-weight:bold;
}
</style>

</head>
<body>
<div id="storyContainer">
<div id="story1" class="storydiv">
	<a href="http://www.builderau.com.au/program/iis/soa/Protect_IIS_log_files_by_moving_them_to_a_secure_location/0,339028427,339271617,00.htm" class="ched">Secure IIS</a>
	   <span class="storydesc">
	   Log files are essential to reconstruct events before an IIS Web server failure. Learn how to protect your log files with this tip.</span>
	  <span class="fstory"><a href="http://www.cnet.com.au/software/security/0,39029558,40058242,00.htm">Full story</a></span>
</div>
<div id="story2" class="storydiv">
	<a href="http://www.builderau.com.au/program/html/soa/Microformats_and_Mapping/0,339028420,339271486,00.htm" class="ched">User Group Mash</a>
		   <span class="storydesc">
	   Find an Aussie user group near you with our new Google maps interface.</span>
	  <span class="fstory"><a href="http://www.builderau.com.au/program/html/soa/Microformats_and_Mapping/0,339028420,339271486,00.htm">Full story</a></span>
</div>
<div id="story3" class="storydiv">
	<a href="http://www.builderau.com.au/program/dotnet/soa/Quick_Start_guide_to_Microsoft_NET_development/0,339028399,339271495,00.htm" class="ched">.NET 101</a>
		   <span class="storydesc">
	   Learn how the .NET Framework works and the tools you'll need to get up and running in this quick start guide.</span>
	  <span class="fstory"><a href="http://www.builderau.com.au/program/dotnet/soa/Quick_Start_guide_to_Microsoft_NET_development/0,339028399,339271495,00.htm">Full story</a></span>
</div>
<div id="story4" class="storydiv">
	<a href="http://www.builderau.com.au/program/css/soa/Understanding_the_CSS_box_model/0,39028392,39269220,00.htm" class="ched">Understand CSS</a>
		   <span class="storydesc">
	   Before diving into CSS learn<br/>some of the core drivers and concepts.</span>

	  <span class="fstory"><a href="http://www.builderau.com.au/program/css/soa/Understanding_the_CSS_box_model/0,39028392,39269220,00.htm">Full story</a></span>
</div>

</div>
</body>
</html>

Which is great, but it's hardly going to rotate properly if it is all one after another vertically. To get all the divs to sit on top of each another, we add the following line to the storydiv class:

position:absolute;

Now we have a huge mess. To get some order into it, we hide the divs with id story 2 thorugh to 4 with:

display:none

This is how our carousel will appear like when we load it - it's time to get into the JavaScript.

Bringing in the JavaScript

The defining feature of a carousel is the rotating content, therefore we will be using some cheap CSS tricks to simply hide and show the divs. We will be using the following code:


<script>
var stor = -1;
var maxstor = 3;
var timeout = 3500;

function autorot() {
	showNext();
	timeout = setTimeout('autorot();', timeout);
}

function rotateDiv(stor){
  var divs = document.getElementById("storyContainer").getElementsByTagName("div");
  for (var i=0; i < divs.length; i++ ) {
    var div = divs[i];
    if ( (div.id != "")) {
	if(i != stor){
        	div.style.display = "none";
	}
	else{
		div.style.display = "block";
	}
    }
  }
}

function showNext(){
	if(stor < maxstor)
		stor++;
	else
		stor=0;

	rotateDiv(stor);
}
</script>

and on the body tag we put:

<body  onload="autorot()">

What is happening here is that when the page laods the autorot function is called, which in turn calls the showNext function and then sets up a timeout that recalls itself in 3.5 seconds - this timeout is what keeps the carousel turning over.
The showNext method simply determines which story is going to be shown and passes it to the rotateDiv function, where all the action happens. rotateDiv fetches all the divs that are children of the storyContainer div and sets their style.display variable to none unless it is the story we wish to see, in which case it is set to block.

Now we have a functional carousel - yet it is hardly a thing of beauty or usability. Let's change that.

Navigation

Carousel's provide a quick way to show many different pieces of content, a tradeoff is usually made between rotation speed and the ability to actually read the content beyond the headline. Enter the need for navigation links.

We are going to add a div for the navigation links that will be able to jump us to any of the four stories and also give us the ability to control the carousel's display with previous and next story links.

Here is our navigation HTML that we insert before the closed body tag:

<div id="nav"><a href="javascript:showPrev()" onClick="stoprot()"><< Prev</a> | <span id="nav1"><a href="javascript:showStoryOne()" onClick="stoprot()">1</a></span> | <span id="nav2"><a href="javascript:showStoryTwo()" onClick="stoprot()">2</a></span> | <span id="nav3"><a href="javascript:showStoryThree()" onClick="stoprot()">3</a></span> | <span id="nav4"><a href="javascript:showStoryFour()" onClick="stoprot()">4</a></span> | <a href="javascript:showNext()" onClick="stoprot()">Next >></a></div>
As can be seen, we are going to need some more JavaScript functions, here they are:
function showNext(){
	if(stor < maxstor)
		stor++;
	else
		stor=0;

	rotateDiv(stor);
}

function stoprot() {
	clearTimeout(timeout);
}


function showNext(){
	if(stor < maxstor)
		stor++;
	else
		stor=0;

	rotateDiv(stor);
}

function showPrev(){
	if(stor > 0)
		stor—;
	else
		stor=maxstor;

	rotateDiv(stor);
}

function showStoryOne(){
	stor=0;
	rotateDiv(stor);
}
function showStoryTwo(){
	stor=1;
	rotateDiv(stor);
}
function showStoryThree(){
	stor=2;
	rotateDiv(stor);
}
function showStoryFour(){
	stor=3;
	rotateDiv(stor);
}

Nothing spectacular, but needed. We also need to change the rotateDiv function to update which story is currently being shown, below is the code for it:


function rotateDiv(stor){
  var divs = document.getElementById("storyContainer").getElementsByTagName("div");
  for (var i=0; i < divs.length; i++ ) {
    var div = divs[i];
    if ( (div.id != "")) {
	if(i != stor){
        	div.style.display = "none";
	}
	else{
		div.style.display = "block";
	}
    }
  }
  
    var spans = document.getElementById("nav").getElementsByTagName("span");
  for (var i=0; i < spans.length; i++ ) {
    var span = spans[i];
    if ( (span.id != "")) {
	if(i != stor)
        	span.className = "none";
	else
		span.className = "selStory";
    }
  }
}

Because there are some new styles, we need to add them in the stylesheet:

#nav { 
	font-size:12px;
	position:absolute;
	top:100px;
	left:325px;
}

.selStory {
	background:#eee;
	border:1px solid #777;
}

And that it is it, our rather spartan carousel is feature complete, view the entire code to date here.

Adding Effects - Making it really annoying cool

Thanks to the prototype and scriptaculous we can really pimp this ride out. We'll be adding some effects now that can at least simulate what we see in the Flash counterparts.

With a little bit more work and some creativity, I'm sure that you can create a better carousel that far outdoes my quick creation.

When not to use JavaScript

Knowing when to use JavaScript is not enough, to get the best results one should also know when not to use JavaScript. The more advanced that you wish to get the less advantageous it is to use JavaScript.

There is absolutely no way that JavaScript can compete with Flash when it comes to the latest and greatest in eye-catching effects, the amount of time needed to reach the same level far outweighs the disadvantages of Flash.

If you need to use video at all then flv is one of the best formats to use for the Web. There is a reason that YouTube and Google Video make use of a flash player.

Once you start to get more and more involved in JavaScript, the more that the little browser inconsistencies come into play. A great way around this is to standardise the platform, exactly the sort of environment that Flash is suited for.

Conclusion

It's taken a bit of work and a few cups of coffee to get here, but this is the end.

One thing to remember is that if you fanatically try to replace Flash then you are no better than the people that try to fanatically deploy Flash.

If all you need is a simple rotation then javascript could be your ticket, if you need advanced animation and all sorts of visual trickery then Flash would be your thing.

Remember to try to use the right tool for the right job.

About Chris Duckett

Some would say that it is a long way from software engineering to journalism, others would correctly argue that it is a mere 10 metres according to the floor plan.During his first five years with CBS Interactive, Chris started his journalistic advent...

Editor's Picks

Free Newsletters, In your Inbox