Creating a Slick Auto-Playing Featured Content Slider

Chris Coyier //

I love the Coda Slider plugin for jQuery. I've used it recently to build a couple of tabbed "widgets". One here on CSS-Tricks in the sidebar to show Script & Style links, Featured Posts, and Popular Posts. Just kind of a fun way to show lots of content in a small area. I also used it on an article for NETTUTS for a similar purpose.

Both of these examples use the Coda Slider pretty much "out of the box". Sure the design was heavily altered to fit the job, but the actual functionality wasn't altered in any way. I recently had the calling to build a "featured content area". The Coda Slider fit the bill almost perfectly, but it needed a little functionality surgery to do what I wanted it to do. Special thanks to Benjamin Sterling for helping me out and figuring out some quirks for me.

View Demo   Download Files

Functionality Checklist

Like I said, the Coda Slider was 90% there already. There is a main content area (panels, if you will), which slide from left to right each with different unique content. There is generally a set number of panels, but the code is written in such a way that adding or removing panels isn't a huge pain. There are links which act as navigation to quickly jump to any particular panel. These links can be anything (text hyperlink, thumbnail, etc) and link to a unique hash value URL (each panel has a unique URL if need be). Coda Slider provides all of this out of the box.

Here is what we need in addition:

  • Different types of custom content in the panels. We can already put whatever we want in the panels, but to make it easier on ourselves, there will be a couple of different formats ready to go. The main one being an image the size of the entire panel, but featuring a text-overlay. DONE.
  • Auto-play. You can still click the thumbnails to jump to any panel, but left onto itself, the slider will slowly cycle through the panels. ADDED, SEE BELOW.
  • Arrow indicator. To serve as a visual indication of which panel you are currently viewing, a small arrow will display above the thumbnail pointing into the panel. ADDED.

Let's go through the HTML, CSS, and JavaScript.

The HTML

Here is the framework HTML for just the slider itself:

<div class="slider-wrap">
	<div id="main-photo-slider" class="csw">
		<div class="panelContainer">

			<div class="panel" title="Panel 1">
				<div class="wrapper">
					<!-- REGULAR IMAGE PANEL -->
					<img src="images/tempphoto-1.jpg" alt="temp" />
					<div class="photo-meta-data">
						Photo Credit: <a href="http://flickr.com/photos/astrolondon/2396265240/">Kaustav Bhattacharya</a><br />
						<span>"Free Tibet" Protest at the Olympic Torch Rally</span>
					</div>
				</div>
			</div>
			<div class="panel" title="Panel 2">
				<div class="wrapper">
					<!-- PANEL CONTENT -->
				</div>
			</div>		
			<div class="panel" title="Panel 3">
				<div class="wrapper">
					<!-- EXAMPLE OF OTHER PANEL POSSIBILITIES -->
					<img src="images/scotch-egg.jpg" alt="scotch egg" class="floatLeft"/>
			
					<h1>How to Cook a Scotch Egg</h1>
			
					<ul>
						<li>6 hard-boiled eggs, well chilled (i try to cook them to just past soft boiled stage, then stick them in the coldest part of the fridge to firm up)</li>
						<li>1 pound good quality sausage meat (i used ground turkey meat, seasoned with sage, white pepper, salt and a tiny bit of maple syrup)</li>
						<li>1/2 cup AP flour</li>
						<li>1-2 eggs, beaten</li>
						<li>3/4 cup panko-style bread crumbs</li>
						<li>Vegetable oil for frying</li>
					</ul>
				</div>
			</div>
			<div class="panel" title="Panel 4">
				<div class="wrapper">
					<!-- PANEL CONTENT -->
				</div>
			</div>
			<div class="panel" title="Panel 5">
				<div class="wrapper">
					<!-- PANEL CONTENT -->
				</div>
			</div>
			<div class="panel" title="Panel 6">
				<div class="wrapper">
					<!-- PANEL CONTENT -->
				</div>
			</div>

		</div>
	</div>

	<!-- TO MAKE THESE THUMBNAILS ACTUALLY WORK, BOTH THE HASH VALUE (#1, ETC.)
          AND THE CLASS="CROSS-LINK" ARE REQUIRED -->

	<a href="#1" class="cross-link active-thumb"><img src="images/tempphoto-1thumb.jpg" class="nav-thumb" alt="temp-thumb" /></a>
	<div id="movers-row">
		<div><a href="#2" class="cross-link"><img src="images/tempphoto-2thumb.jpg" class="nav-thumb" alt="temp-thumb" /></a></div>
		<div><a href="#3" class="cross-link"><img src="images/tempphoto-3thumb.jpg" class="nav-thumb" alt="temp-thumb" /></a></div>
		<div><a href="#4" class="cross-link"><img src="images/tempphoto-4thumb.jpg" class="nav-thumb" alt="temp-thumb" /></a></div>
		<div><a href="#5" class="cross-link"><img src="images/tempphoto-5thumb.jpg" class="nav-thumb" alt="temp-thumb" /></a></div>
		<div><a href="#6" class="cross-link"><img src="images/tempphoto-6thumb.jpg" class="nav-thumb" alt="temp-thumb" /></a></div>
	</div>

</div>

The CSS

The full CSS for this example has a basic reset, some utility styles and basic structure. Below, I'll just show you the CSS relevant to the slider itself, but you can view the full CSS here.

.slider-wrap						{ width: 419px; position: absolute; top: 87px; left: 40px; }			
.stripViewer .panelContainer 
.panel ul						{ text-align: left; margin: 0 15px 0 30px; }
.stripViewer						{ position: relative; overflow: hidden; width: 419px; height: 285px; }
.stripViewer .panelContainer				{ position: relative; left: 0; top: 0; }
.stripViewer .panelContainer .panel			{ float: left; height: 100%; position: relative; width: 419px; }
.stripNavL, .stripNavR, .stripNav			{ display: none; }
.nav-thumb 						{ border: 1px solid black; margin-right: 5px; }
#movers-row						{ margin: -43px 0 0 62px; }
#movers-row div					{ width: 20%; float: left; }
#movers-row div a.cross-link 				{ float: right; }
.photo-meta-data					{ background: url(images/transpBlack.png); padding: 10px; height: 30px; 
											  margin-top: -50px; position: relative; z-index: 9999; color: white; }
.photo-meta-data span 					{ font-size: 13px; }
.cross-link						{ display: block; width: 62px; margin-top: -14px; 
											  position: relative; padding-top: 15px; z-index: 9999; }
.active-thumb 						{ background: transparent url(images/icon-uparrowsmallwhite.png) top center no-repeat; }

Anything in there that starts with ".strip" is core to the slider itself, getting those panels set up and the wrapper around them, all the CSS magic needed to make a slider do its thing. From ".nav-thumb" on down is stuff specific to this example. The thumbnails have thin black borders. The meta-data section is pushed off the panel by the image, but then is forced back up with a negative top margin and a transparent black background applied.

The ".active-thumb" class is very important too, if a thumbnail has this class, it gets the special background applied, which is the white arrow we wanted to indicate the current panel. This class will get applied and removed in the JavaScript.

The JavaScript

In the header section of your HTML, you'll need to include jQuery and all the plugin files. The bare minimum basics look like this:

<script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="js/jquery-easing-1.3.pack.js"></script>
<script type="text/javascript" src="js/jquery-easing-compatibility.1.2.pack.js"></script>
<script type="text/javascript" src="js/coda-slider.1.1.1.pack.js"></script>
	
<script type="text/javascript">
	$(function(){
			
		$("#main-photo-slider").codaSlider();

	});
</script>

That will activate the slider, but remember we have some extra functionality to get cooking here. Instead of altering the plugin itself, we can add the extras by writing our own little function on top of it. In essence, to achieve the "auto-play" effect, we are going to trigger a click event on the next thumbnail in line every 3 seconds. We'll call the function "theInterval", and we'll need a couple of variables, so we'll set those up first.

var theInt = null;
var $crosslink, $navthumb;
var curclicked = 0;

theInterval = function(cur){
	clearInterval(theInt);
	
	if( typeof cur != 'undefined' )
		curclicked = cur;
	
	$crosslink.removeClass("active-thumb");
	$navthumb.eq(curclicked).parent().addClass("active-thumb");
		$(".stripNav ul li a").eq(curclicked).trigger('click');
	
	theInt = setInterval(function(){
		$crosslink.removeClass("active-thumb");
		$navthumb.eq(curclicked).parent().addClass("active-thumb");
		$(".stripNav ul li a").eq(curclicked).trigger('click');
		curclicked++;
		if( 6 == curclicked )
			curclicked = 0;
		
	}, 3000);
};

We aren't done yet though. We need to call our function, for one thing. But we also need to handle a manual click event on one of our thumbnails properly. We want a manual click event to use the same function, so that the "current" thumbnail can be reset properly and we don't see any weird jumping around. Right after our function, we can now add this final code, to be fired when the DOM is ready:

$(function(){
	
	$("#main-photo-slider").codaSlider();
	
	$navthumb = $(".nav-thumb");
	$crosslink = $(".cross-link");
	
	$navthumb
	.click(function() {
		var $this = $(this);
		theInterval($this.parent().attr('href').slice(1) - 1);
		return false;
	});
	
	theInterval();
});

Couple more things to note. Notice the number "6" is hardcoded in our function. If you change the number of thumbs, you'll have to change it here as well. Also, you may have noticed the seemingly strange element that click event is being triggered on (".stripNav ul li a"... where is that?!). You'll notice that isn't anywhere in our HTML. Actually, the Coda Slider plugin automatically generates this unordered list from the number of panels when it runs. Very handy sometimes we we have hidden it in the CSS in our example. We are using them in our function though, as they will be the most reliable elements for the click event. They will exist no matter what, and this example will continue to work and be auto-play regardless if we use the thumbnail navigation or not.

View Demo   Download Files

UPDATE: Auto-Play

Thanks to Jack Reichert:

var $j = jQuery.noConflict();

var theInt = null;
var curclicked = 0;
var stop = 0;

theInterval = function(cur){
       clearInterval(theInt);

       theInt = setInterval(function(){
               $j(".coda-nav-right a").eq(curclicked).trigger('click');
               curclicked++;
               if( 10 == curclicked )
                       curclicked = 0;
               $j("#stop").click(
                       function(){
                               if (stop==0){
                               clearInterval(theInt);
                               stop=1;}
                       });
       }, 750);
       $j("#stop").click(
               function(){
                       stop=0;
                       theInterval();
               }
       );
};
$j(function(){
       $j("#main-photo-slider").prepend('<div id="stop">Start/Stop</div>');
       $j("#main-photo-slider").codaSlider();
       theInterval();
});