Tutorial: A jQuery Slideshow for a Good Cause

January 14, 2010
Development

We recently launched a site for a new nonprofit called Striving for More. The project was a lot of fun. The site is great-looking, has some cool features, and more importantly it was for a good cause.

In this post, I am going to cover one of the more important features of the site: an interactive gallery that tells Colleen's Story. I'll breakdown how it was built and the reasons for doing some of the things the way I did. It ends up being very simple and a great example of the power that can be had by combining and tweaking jQuery plugins.

Here is the final product so you can see where this is headed:

What is it?

Colleen's Story is a simple slideshow that can be navigated in any order with an introduction screen. Each slide has a nice navigation button, some narrative and a cool graphic. Because we didn't want the navigation to move around, the content needed to scroll in place, another requirement. For something that looked this good, overflow: auto; wouldn't cut it. After doing some looking around, I decided to use the following plugins for the project:

  • Cycle - This is one of my favorite plugins. If you haven't checked it out you need to. With some improvments that have come in the last 6 months or so it is the only plugin you'll ever need for rotating content. We've rolled our own cycle-like jquery code in the past, but that is rarely necessary. On this project, Cycle will handle all of the slide transitions as well as the navigation.
  • jScrollPane - I'm not generally a fan of replacing the default behavior of browsers, but this situation required it. I played around with serveral plugins before settling on this one which seems to have the fewest downsides.

The HTML

To use these plugins will require that we structure our html in a certain way. Here is how it is setup:

<div id="gallery">
	<div id="gallery-intro">
		[Introduction Content]
		<a href="javascript:void(0);" id="startslides">Begin</a>
	</div>
	<div id="gallery-slides" class="hidden">
		<ol>
			<li id="slide-[slidenum]">
				<div class="slide-content">
					<h2>[Slide Title]</h2>
					<div class="scroll-content">
					[Slide Content]
					</div>
				</div>
				<img class="slide-image" src="[Slide Image]" alt="" />
			</li>
			...
		</ol>
	</div><!-- gallery-slides -->
	<div id="gallery-nav">
		<ol>
			<li id="slide-1-nav">1. Monkey</li>
			<li id="slide-2-nav">2. Necklace</li>
			<li id="slide-3-nav">3. IV Beads</li>
			<li id="slide-4-nav">4. Bag</li>
			<li id="slide-5-nav">5. Blistex</li>
			<li id="slide-6-nav">6. Notebook</li>
			<li id="slide-7-nav">7. Pink Hair</li>
		</ol>
	</div><!-- gallery-nav -->
</div><!-- gallery -->

There are some things to point out here:

    • The Gallery Intro

      Before the slideshow is shown, a description of its purpose is shown. This is grouped independently of the slides. The plan is to make this disappear once the slideshow is started.

The group of slides

All Cycle asks for is a group of slides that are children to one element. In this case it is the ol. We'll end up calling cycle on "#gallery-slides ol". Also notice that I have given this the class "hidden". I do this so that I can hide the slides with css rather than javascript. This is important to do, otherwise while the page loads they will flash.

  • The Navigation

    Cycle provides a navigation (pager) generator. For this project I wanted to have all of my html in one place and give good text descriptions for each slide. Having this dynamicly match the number of slides didn't matter either because these were set in stone. Instead, I just used an id attribute convetion so I could write some simple javascript to link the navigation to the slides.

  • Scroll-Content Class

    I wrapped the content of each slide in a container with the class "scroll-content". This is so that we can target it if necessary using the jScrollPane plugin.

The CSS

A concern with this site due to the texture used was download size. While the end result is not perfect, it was taken into consideration when putting this together. The overall strategy was to use one background image for the slideshow frame and let the slide text, images and navigation float over it. One concession was to also include some of the background in the slide images. While this made for some redundant information, the use of jpg compression instead of a 24-bit or even 8-bit png more than made up for it. Finally, sprites were used for the navigation.

Here is the major layout css:

/* Container */
#gallery { position: relative; width: 696px; height: 494px; background: url('gallery-background.jpg'); }

/* Intro Container */
#gallery-intro { position: absolute; top: 8px; left: 9px; height: 268px; width: 459px; padding: 70px 110px;
				font: italic 16px Georgia,serif; color: #1e5584; line-height: 32px; text-align: center; }
#gallery-intro strong { color: #bc9906; display: block; font-weight: normal; }
#startslides { width: 116px; height: 30px; display: block; margin: 20px auto; background: url('gallery-begin.jpg'); text-indent: -9999em; }

/* Slides */
#gallery-slides { position: absolute; top: 8px; left: 9px; height: 408px; width: 679px; overflow: hidden; background: transparent; }
#gallery-slides ol { position: absolute; top: 0; left: 0; list-style: none; margin: 0; padding: 0; width: 679px; height: 408px; background: transparent; }
#gallery-slides ol li { width: 629px; height: 338px; padding: 25px; }

/* Slide Components */
#gallery-slides .slide-content { width: 340px; padding-right: 20px; height: 338px; line-height: 18px; z-index: 2; }
#gallery-slides .scroll-content { overflow: auto; width: 320px; padding-right: 20px; height: 315px; }
#gallery-slides .slide-content p { margin: 6px 0; }
#gallery-slides .slide-content h2 { margin: 0px 0 6px 0; font: italic 25px Georgia,serif; color: #bc9906;  }
#gallery-slides .slide-image { position: absolute; bottom: -25px; right: 1px; z-index: 1; }

The quick things to notice are:

  • The container is positioned relative so that everything else can be placed absolute inside of it.
  • ".scroll-content" has overflow set to auto. This is required for the jScrollPane plugin.

The navigation was also positioned absolute and set up with a basic CSS sprites technique. You can see the image used here. I am using '.on' in addition to the ':hover' pseudo-class so that we can get the hover states to work in IE6 using javascript. You can get more information on this technique in detail in a classic article on A List Apart. For those of you interested in using the technique for navigation menus, I've also written a plugin to make that dead simple called jQuery AutoSprites.

#gallery-nav { position: absolute; top: 425px; left: 8px; width: 680px; height: 50px; }
#gallery-nav ol { position: absolute; margin: 0; padding: 0; top: 0; left: 0; width: 680px; height: 50px; background: url('gallery-sprites.jpg'); }
#gallery-nav ol li { list-style: none; margin: 0; padding: 0; position: absolute; top: 0; left: 100px; width: 85px; height: 50px; text-indent: -9999em; cursor: pointer; cursor: hand; }
#gallery-nav ol li.activeslide, #gallery-nav ol li.hov { background-image: url('images/gallery-sprites.jpg'); }
	#gallery-nav #slide-1-nav { left: 0px; width: 100px; }
	#gallery-nav #slide-1-nav.activeslide, #gallery-nav #slide-1-nav.hov{ background-position: 0px -50px; }
	#gallery-nav #slide-2-nav { left: 97px; width: 100px; }
	#gallery-nav #slide-2-nav.activeslide, #gallery-nav #slide-2-nav.hov { background-position: -97px -50px; }
	#gallery-nav #slide-3-nav { left: 194px; width: 100px; }
	#gallery-nav #slide-3-nav.activeslide, #gallery-nav #slide-3-nav.hov { background-position: -194px -50px; }
	#gallery-nav #slide-4-nav { left: 291px; width: 100px; }
	#gallery-nav #slide-4-nav.activeslide, #gallery-nav #slide-4-nav.hov { background-position: -291px -50px; }
	#gallery-nav #slide-5-nav { left: 388px; width: 100px; }
	#gallery-nav #slide-5-nav.activeslide, #gallery-nav #slide-5-nav.hov{ background-position: -388px -50px; }
	#gallery-nav #slide-6-nav { left: 485px; width: 100px; }
	#gallery-nav #slide-6-nav.activeslide, #gallery-nav #slide-6-nav.hov { background-position: -485px -50px; }
	#gallery-nav #slide-7-nav { left: 582px; width: 100px; }
	#gallery-nav #slide-7-nav.activeslide, #gallery-nav #slide-7-nav.hov { background-position: -582px -50px; }

The Javascript

Since our plugins come with quite a bit out of the box it is really simple to get the jQuery running. The first step was to handle the items hidden by css I described above. We can do this right away since the javascript will execute quickly once it gets going as it will be replaced bya jQuery hide.

$('.hidden').removeClass('hidden');
$('#gallery-slides').hide();

Next I got the navigation hover states working in IE6 which needs javascript since it doesn't recognize the :hover psuedo-class on non-anchor elements.

$('#gallery-nav ol li').hover(
	function(){ $(this).addClass('hov'); },
	function(){ $(this).removeClass('hov'); }
);

Next was the simple step of enabling jScrollPane. Don't forget to set these containers as overflow:auto in the css too.

$('#gallery-slides .scroll-content').jScrollPane({
	scrollbarWidth: '10'
});

Setting up a jQuery Cycle is easy, but there was a trick needed for IE. Because I used the fade effect, Cycle sets a background color during the transition to get the text fading to work correctly. I reset this to transparent once the transition is over using the after callback. While this may seem like a pain, little features like this are part of the reason to use established plugins over something homegrown.

$('#gallery-slides ol').cycle({
	timeout: 0,
	fx: 'fade',
	after: function(){
		$('#gallery-slides ol li').css('background', 'transparent');
	}
});

The last step is adding the custom navigation features. You'll notice that the id of the nav item is used to figure out which slide to show. I also set up the swap between the intro and the slides to occur if either the navigation or "Begin" button is pressed.

$('#gallery-nav ol li').click(function(){
	$('#gallery-slides').fadeIn();
	$('#gallery-intro').fadeOut();
	$(this).parent().children().removeClass('activeslide');
	$(this).addClass('activeslide');
	var slidenum = Number($(this).attr('id').substr(6,1)) - 1;
	$('#gallery-slides ol').cycle(slidenum);	
});
$('#startslides').click(function(){
	$('#gallery-slides').fadeIn();
	$('#gallery-intro').fadeOut();
	$('#slide-1-nav').trigger('click');
});

Conclusion

So that's it. Once again you can check out the final product on the Striving for More site. Next week I'll post a tutorial about how the homepage slider was done entirely from scractch. If you want to read about that when it comes out, you should subscribe to the blog.

Comments

Ana's avatar
Ana
If you want to reinforce ie6 with some modern features hover, target and other features and fixed some bugs too you can try
http://code.google.com/p/ie7-js/
Actually is in fact ie9.js and you have google hosting too
nitin's avatar
nitin
thanx for the slide show
soegengku's avatar
soegengku

...this is a great tutorial...

website laten maken's avatar
website laten maken

Great job! I really like the rest of the site to, very well done :-)

One thing: I don't like the cursor changing to the text selection symbol when hovering the items in the main navigation. Just a small thing. Besides that, very great job!

Joel Sutherland's avatar
Joel Sutherland NMC team member

Thanks Ben! It really is a great cause.

Ben Requena's avatar
Ben Requena

Number 5 of Colleen's story made me smile.
What a great story.

...and the jQuery stuff isn't bad either.

Leave a comment