How to Create a Slideshow Plugin with jQuery

How to Create a Slideshow Plugin with jQuery

There are hundreds of slideshow plugins out there, from all time favorites like Lightbox to the most advanced like Galleria. You might think, why make another one?. Well, most of us are using plugins like these on our websites, so why not use our own?

If you use slideshow plugins frequently you may realize that there are basically two different types, the ones that slide and the ones with effects that don’t slide. Choosing one or the other depends on the approach you take when coding it.

In this tutorial I’ll discuss the creation process of Powerslide, a plugin I just released that follows the “effects” approach. You should have a basic knowledge of HTML, CSS and jQuery to follow this tutorial.

How to Create a Slideshow Plugin with jQuery

[tut demo=”http://www.onextrapixel.com/examples/slideshow-plugin/” download=”http://www.onextrapixel.com/examples/slideshow-plugin/slideshow-plugin.zip”]

Project Setup

I suggest you download this project setup template. It’ll be easier than having to create all the files and link them. It has all you need to get started with this tutorial. If you decide to use your own project template keep in mind that the relative paths might change.

This is how the project template looks:

Setup

960gs and modernizr are not necessary but they’re really useful. We’re not going to use a separate IE stylesheet but you might need it if you want to mess with IE later.

The Structure

We’re going to start with the bare bones of the slider.

First, let’s set the base HTML for the slideshow in index.html:

<div id="slider">
	<img src="img/img1.jpg" title="caption" />
	<img src="img/img2.jpg" title="caption" />
	<img src="img/img3.jpg" title="caption" />
</div>

Let’s also call the jQuery plugin on document load in js/scripts.js:

$(function(){
	$('#slider').powerSlide();
});

Now, we have everything we need to start coding the plugin.

Let’s take a look at the structure we want to achieve:

Structure

The following code serves only as preview. This is what we will be generating with jQuery.

<div class="powerSlide">
	<div class="wrapper">
		<a href="" class="prev"></a>
		<a href="" class="next"></a>
		<div class="image">
			<img src="" alt="" />
			<p></p>
		</div>
	</div>
	<div class="nav"></div>
</div>

We need to generate all these elements in the DOM from the original HTML. So, let’s begin with a basic jQuery plugin template.

Open js/powerSlide.js.

(function($){
	$.fn.powerSlide = function(options {  

		var opt = {
			// Options
		};

		return this.each(function() {        
			if (options) { 
				$.extend(opt, options);
			}
			/* Code goes here */			
		});
	};
})(jQuery);

Options are the variables that we can specify when calling the plugin on an element. These are the options we want to be able to change with their default values.

'width': 908, // Width and height of the images
'height': 340,
'position': 'bottom', // Position of the navigation
'bullets': false, // Show numbering navigation
'thumbs':  true, // Show thumbnail navigation
'row': 10, // Thumbnails per row
'auto': true, // Auto rotate
'autoSpeed': 4000,
'fadeSpeed': 1000

Now we can use the options with opt.option. For example, to use the width value we would write opt.width.

Inside the “each loop” and with the structure already in mind, we need to create the elements and assign them to variables so it’s easier to refer to them later. Using firebug or the webkit developer tools we can track the elements as they’re being created in the DOM.

/* Container and wrapper 
-----------------------------------------------*/ 
$(this).children().wrapAll('<div class="powerSlide" />'); 
var container = $(this).find('.powerSlide'); 
container.find('img').wrapAll('<div class="wrapper" />'); 
var wrapper = container.find('.wrapper'); 

/* Previous & next buttons 
-----------------------------------------------*/ 
wrapper.append('<a href="#" class="prev">Prev</a><a href="#" class="next">Next</a>'); 

/* Navigation & captions 
-----------------------------------------------*/ 
switch (opt.position) { // Navigation position 
		case 'top': container.prepend('<div class="nav" />'); break; 
		case 'bottom': container.append('<div class="nav" />'); break; 
} 

var nav = container.find('.nav'); 

wrapper.find('img').each(function(i){ 

	i += 1; // Start numbers at 1 

	if (opt.bullets === true) { // Bullet navigation 
			nav.append('<a href="#">'+ i +'</a>'); 
	} 

	if (opt.thumbs === true) { // Thumbnail navigation 
			nav.addClass('thumbs').append( 
				'<img class="thumb" src="'+ 
				$(this).attr('src') +'" alt=""/>'); 
	} 

	// Captions 
	var title = $(this).attr('title'); 
	$(this).wrapAll('<div class="image" />'); 
	if (title !== undefined) { 
			$(this).attr('title', ''); 
			$(this).after('<p>'+ title +'</p>'); 
	} 
});			 

You can now try changing the plugin options values to test different situations. Once the elements are created we can dive into the css.

This is just for the layout, but we will create a separate theme file for all the color customization and CSS3 goodness. This will help to keep the code clean and it’ll be easier to create new themes later on.

Let’s open css/powerSlide.css.

/* Wrapper
-------------------------------------------*/
.powerSlide .wrapper {
	overflow: hidden;
	padding: 15px;
	position: relative;
}

/* Image
-------------------------------------------*/
.powerSlide .wrapper img {
	position: absolute; /* They key to the “effects” approach */
}

/* Prev & Next buttons
-------------------------------------------*/
.powerSlide a.prev,
.powerSlide a.next {
	display: none;
	margin-top: -1em; /* Same as padding-top */
	padding: 1em 2em;
	position: absolute;
	text-decoration: none;
	top: 50%;
}
.powerSlide a.next {
	right: 0;
}

/* Caption
-------------------------------------------*/
.powerSlide .wrapper p {
	bottom: 0;
	display: none;
	padding: 1.5em;
	position: absolute;
}

/* Navigation
-------------------------------------------*/
.powerSlide .nav {
	margin: .5em 0;
	overflow: hidden;
}
.powerSlide .nav.thumbs {
	padding: 15px; /* Same as wrapper padding */
}
.powerSlide .nav img.thumb {
	cursor: pointer;
	float: left;
	margin: 2px;
	position: relative;
}
.powerSlide .nav img.thumb.current { /* Current thumbnail */
	z-index: 999;
}
.powerSlide .nav a {
	float:left;
	margin: .2em;
	min-width: 1em;
	padding: .2em .7em;
	text-align: center;
	text-decoration: none;
}
.powerSlide .nav a.current {} /* Current bullet */

As you can see the CSS is pretty straightforward. Elements that are inside the container have to be absolute positioned. Also be careful with margins and padding. We will generate the dimensions later on with jQuery.

The Slider Object

To store all the information and actions of the slider we’re going to use an object. The most important concept of a slider is the index. We need to know the index of any given image at any time. The index will allow us to have control over which image needs to be shown when we trigger an event.

Here’s a list of all the variables and a short description of what each one does.

  • imgs: the selector for all images.
  • imgCount: the number of images in the selection.
  • navNext: the next button.
  • navPrev: the previous button.
  • bullets: selector for all bullets in numbered navigation.
  • thumbs: selector for all thumbnails in thumbnail navigation.
  • captions: selector for all captions.
  • getCurrentIndex(): get the index of the current image at any given time.
  • go(index): go to an image of any given index.
  • next(): go to the next image.
  • prev(): go to the previous image.
  • init(): set width and height of the slideshow and calculte dimensions of dynamic elements.
/* Slider Object 
-----------------------------------------------*/		 
var Slider = function(){ 

this.imgs = wrapper.find('div.image'); 
this.imgCount = (this.imgs.length) - 1; // Match index 
this.navPrev = wrapper.find('a.prev'); 
this.navNext = wrapper.find('a.next'); 
this.bullets = container.find('.nav a'); 
this.thumbs = container.find('.nav img.thumb'); 
this.captions = this.imgs.find('p'); 

this.getCurrentIndex = function(){ // Index 
	return this.imgs.filter('.current').index(); 
}; 

this.go = function(index){ // Rotate images 
	this.imgs 
		.removeClass('current') 
		.fadeOut(opt.fadeSpeed) 
		.eq(index) 
		.fadeIn(opt.fadeSpeed) 
		.addClass('current'); 
	this.bullets 
		.removeClass('current') 
		.eq(index) 
		.addClass('current'); 
	this.thumbs 
		.removeClass('current') 
		.eq(index) 
		.addClass('current'); 
}; 

this.next = function(){ 
	var index = this.getCurrentIndex(); 
	if (index < this.imgCount) { 
		this.go(index + 1); // Go next 
	} else { 
		this.go(0); // If last go first 
	} 
}; 

this.prev = function(){ 
	var index = this.getCurrentIndex(); 
	if (index > 0) { 
		this.go(index - 1); // Go previous 
	} else { 
		this.go(this.imgCount); // If first go last 
	} 
};	 

this.init = function(){ // Init
	wrapper
		.width(opt.width)
		.height(opt.height); /* Set width and height */
	
	this.imgs.hide().first().addClass('current').show(); /* Set current image */
	this.bullets.first().addClass('current');
	this.thumbs.first().addClass('current');
	
	// Dimensions for thumbnails and captions
	var padding = wrapper.css('padding-left').replace('px', '');
	var captionsPadding = this.captions.css('padding-left').replace('px', '');
	nav.width(opt.width);
	if (opt.thumbs === true) { // thumbs
		var thumbBorder = this.thumbs.css('border-left-width').replace('px', '');
		var thumbMargin = this.thumbs.css('margin-right').replace('px', '');
		var thumbMaxWidth = opt.width/opt.row;
		this.thumbs.width( (thumbMaxWidth - (thumbMargin * 2)) - (thumbBorder * 2) );
	}
	this.captions // captions
		.width(opt.width - (captionsPadding * 2) + 'px')
		.css('margin-bottom', padding + 'px');
	this.navNext.css('margin-right', padding + 'px');
    }; 

};

Now that the object is defined we have to create a new instance and load it with the init() function.

var slider = new Slider();
slider.init();

Events

Mouse Events

We want to trigger the following events:

  • Click next and go to next image
  • Click prev and go to previous image
  • Click on a numbered bullet and go to that image
  • Click on thumbnail and go to that image
  • Hover image and show caption and buttons

We have to disable the default behavior of the link items with e.preventDefault() to avoid jumping to the top of the page when clicking on empty links.

Also make sure you hide the captions when not hovering over the image. I think the code for this part could be DRYer but it’s good for readability.

wrapper.hover(function(){ // Hover image wrapper
	slider.captions.stop(true, true).fadeToggle();
	slider.navNext.stop(true, true).fadeToggle();
	slider.navPrev.stop(true, true).fadeToggle();
});
slider.navNext.click(function(e){ // Click next button
	e.preventDefault();
	slider.next(); 
});
slider.navPrev.click(function(e){ // Click previous button
	e.preventDefault();
	slider.prev();
});
slider.bullets.click(function(e){  // Click numbered bullet
	e.preventDefault(); slider.captions.hide();
	slider.go($(this).index());
});
slider.thumbs.click(function(){ // Click thumbnail
	slider.captions.hide();
	slider.go($(this).index());
});

Auto Rotate Images

This part is kind of boring, just make sure the caption is hidden when not hovering over the image.

if (opt.auto === true) {
	var timer = function(){
			slider.next();
			slider.captions.hide();
	};
	var interval = setInterval(timer, opt.autoSpeed);
	
	// Pause when hovering image
	wrapper.hover(function(){clearInterval(interval);}, function(){interval=setInterval(timer, opt.autoSpeed);});

	// Reset timer when clicking thumbnail or bullet
	slider.thumbs.click(function(){clearInterval(interval); interval=setInterval(timer, opt.autoSpeed);});
	slider.bullets.click(function(){clearInterval(interval); interval=setInterval(timer, opt.autoSpeed);});	
}

Creating a Theme

Everything should be working at this point. Let’s make it pretty then.

Create the file css/powerSlide_theme.css and include it in index.html.

<link href="css/powerSlide_theme.css" rel="stylesheet" type="text/css" media="screen"/>

And with the help of Colorzilla CSS3 gradient generator let’s add some styles.

/* Wrapper
-------------------------------------------*/
.powerSlide .wrapper {
	background:#fff;
	border:1px solid #999;
}

/* Prev & Next buttons
-------------------------------------------*/
.powerSlide a.prev,
.powerSlide a.next {
	background:#fff;
	box-shadow:2px 0 2px rgba(0,0,0,.3);
	color:#000;
	font:bold 10px Arial;
}
.powerSlide a.next {
	box-shadow:-2px 0 2px rgba(0,0,0,.3);
}

/* Caption
-------------------------------------------*/
.powerSlide .wrapper p {
	background:#000;
	background:rgba(0,0,0,.7);
	color:#fff;
}

/* Navigation
-------------------------------------------*/
.powerSlide .nav.thumbs {
	background:#b5bdc8;
	border:1px solid #999;
}
.powerSlide .nav img.thumb {
margin: 3px;
	box-shadow:0 0 2px #666;
	border: 4px solid transparent;
	filter:alpha(opacity=40);
	opacity:.4;
}
.powerSlide .nav a {
	background:#7d7e7d;
	background:-moz-linear-gradient(top, #7d7e7d 0%, #0e0e0e 100%);
	background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#7d7e7d), color-stop(100%,#0e0e0e));
	background:-webkit-linear-gradient(top,#7d7e7d0%,#0e0e0e100%);
	background:-o-linear-gradient(top,#7d7e7d0%,#0e0e0e100%);
	background:-ms-linear-gradient(top,#7d7e7d0%,#0e0e0e100%);
	background:linear-gradient(top,#7d7e7d0%,#0e0e0e100%);
	border-radius:3px;
	color:#fff;
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#7d7e7d',endColorstr='#0e0e0e',GradientType=0);
	font:bold 12px Arial;
}
.powerSlide .nav img.thumb.current {
	box-shadow:0 0 10px #fff;
	border: 4px solid #fff;
	filter:alpha(opacity=100);
	opacity:1;
}
.powerSlide .nav a.current {
	background:#1e5799;
	background:-moz-linear-gradient(top, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%);
	background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(50%,#2989d8), color-stop(51%,#207cca), color-stop(100%,#7db9e8));
	background:-webkit-linear-gradient(top,#1e57990%,#2989d850%,#207cca51%,#7db9e8100%);
	background:-o-linear-gradient(top,#1e57990%,#2989d850%,#207cca51%,#7db9e8100%);
	background:-ms-linear-gradient(top,#1e57990%,#2989d850%,#207cca51%,#7db9e8100%);
	background:linear-gradient(top,#1e57990%,#2989d850%,#207cca51%,#7db9e8100%);
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#1E5799',endColorstr='#7db9e8',GradientType=0);
}

[tut demo=”http://www.onextrapixel.com/examples/slideshow-plugin/” download=”http://www.onextrapixel.com/examples/slideshow-plugin/slideshow-plugin.zip”]

Notes

The plugin works in IE7+ and all other modern browsers. For some reason, even in IE9, the images don’t fade. This problem must be related to the fadeIn and fadeOut jQuery functions.

Bullets and thumbnails can’t be displayed at the same time but who wants to have them both anyway?

I will be glad to answer any questions. I encourage you to create your own theme and post it here. It’ll be great to have a community theme repository.

Cedric Ruiz is a freelance graphic and web designer/developer with a passion for computers and technology. He actually studied 3D animation but took a totally different path. He needs to learn something new everyday and he loves challenges and teaching people new skills.

Comments

  1. / Reply

    Wow, impressed by the post. Everything is clear enough.
    I’ve used such plug-ins doing http://www.websitetemplates.bz/oscommerce-templates/decor-oscommerce-template_1161.html

  2. / Reply

    You should check out my lightweight and fully customizable content fader/slider on github (http://github.com/jensscherbl/jQuery-Billboard).

    Markup is similar to what you suggest in your article, plus it’s clean coded following the jQuery plugin guidelines.

    Oh, and it works fine in IE, by the way… ;-)

  3. / Reply

    I think this website just became my #1 website for new tools on the web 2.0 era, very nice slideshow came out of this code, thank you very much.

    • Anna Blume,
    • July 2, 2011
    / Reply

    Please, how do I get Links in the captions or photos?

  4. / Reply

    Really solid and well written tutorial – thanks for sharing.

  5. / Reply

    Nice run through a plugin development, just what I was looking for!
    Thanks

  6. / Reply

    nice tutorial! is it possible to use the picture thumbnails instead of numbers?

      • Cedric Ruiz,
      • July 6, 2011
      / Reply

      This tutorial covers how to create numbers as well as thumbnails. You have to pass the value when you call the plugin.
      I created a theme switcher with all the different options and themes available at the powerSlide website.
      http://jqpowerslide.com

      1. / Reply

        cool.. thanks for pointing me to the right direction. cheers mate!

    • John,
    • July 3, 2011
    / Reply

    While “awesome post!” or “Thanks :)” would definitely sum things up..

    The main reason I exceedingly enjoyed this article is that it doesn’t have a microscopic scroll bar and a harry potter book worth of text walking you through each step. I much prefer the clear straight forward approach.

    Easy to understand and great end result.

  7. / Reply

    Hi there.
    For of all, congrats. The slideshow it selfs is looking nice and works well
    But a found a issue with the setInterval function.
    I didnt manage to find what it was. the problem is that after some time the images star to pass to fast and the clearInterval function stops clearing the intervals…and in the end get gets kind of bugged.
    Havent tested in other browser (im using chrome)
    Nice Work

      • Cedric Ruiz,
      • July 6, 2011
      / Reply

      Yes, I noticed that bug too. It happens with chrome when you leave the window and then come back after a while.

        • nei,
        • August 28, 2011
        / Reply

        Same here

          • dimmoon,
          • May 7, 2012
          / Reply

          It’s not only with chrome. This bug happens with Firefox either.

  8. / Reply

    Great tutorial! Do you think it would be possible to trigger the navNext and navPrev by a swipe on a tablet such as the iPad?

    • Ben Bruner,
    • December 8, 2011
    / Reply

    Excellent tutorial, this is exactly what I was looking for!!

    ** I believe I found the error that was occuring in IE. It appears that IE when the div containing the image has the opacity applied, it is not applying the opacity to the image within the div. Therefore, I just added a short bit of code within the ‘this.go’ function to apply the fadeIn and fadeOut to the two images affected as well. After doing that it seemed to work fine in all browsers I tested.

    Thanks again for the simple and easy to follow tutorial.

  9. / Reply

    Great tutorial.
    This was exactly what I was looking for.

    Only thing is that I have the same bug in IE as described in the comments.
    I have tried to change the code in this.go but Im not satisfied with the result.

    Do you have an idea how to solved the bug?

    Thanks!

    • Sid,
    • February 10, 2012
    / Reply

    Awesome tutorial
    Can you tell me the code to change theme and type
    Means how can I make the option to change theme and to change type…
    Please

    • Sid,
    • February 10, 2012
    / Reply

    Hey
    And also can you tell me that how to move it in center
    Please

  10. / Reply

    thank you the script
    i used different size images into the wrapper, how can i move img to center?

    1. / Reply

      i found css. powerSilder:

      .powerSlide .wrapper img {
      position: relative; /* They key to the “effects” approach */
      margin: 0 auto;
      }

    • Ciro,
    • March 27, 2012
    / Reply

    I love this tutorial, i am really just starting in all of this so i am a little confused. I have to create a website for final project and i want to put this slide show into the website. i have follow the steps but i am not sure where am i getting lost. I would really appreciate if you could help me with this. I am fascinated with all of this but i am a little lost.

    Thanks so much

  11. / Reply

    Hi,
    Is there a way of incorporating this excellent slider into a joomla website?
    Oh and centering the images?

    Regards

    Mick

  12. / Reply

    How can i add an image counter for example 1/100 with controls also in use.

    • Amalia,
    • July 20, 2012
    / Reply

    Thank you so much, it helped me a lot!

  13. / Reply

    Finally, A proper slideshow tutorial that moves by itself…
    Great job and very modern!

    • Chris,
    • February 5, 2013
    / Reply

    This has worked well for me so far, however I wondered about customizing it a little. Is there a way for the navigation buttons at the bottom of the page to display words instead of numbered values (1,2,3, etc.)? In my case, the images changing represent months of the calendar. I would like those lower navigation buttons to show ‘December’, ‘January’, ‘February’, etc.

    • Keith,
    • March 1, 2013
    / Reply

    Love your tutorial. Thanks for your efforts. Trying to modify so I can use multiple (2-3) width images. Seems like I would need to identify these images (by the most efficient way possible?), than insert some sort of if statement at the correct place or instance, to change the .wrapper size, and then change back. Any help would be great.

      • Keith,
      • March 1, 2013
      / Reply

      So I ran this ‘if’ statement after the ‘this.thumbs’ chain and seemed to have gotten it to work. Not an expert here, so feedback for better code would be helpful. It would be nice to have some sort of identifier on the pics so as to have the individual widths automatically specified and plug then plugged in as opposed to me individually specifying them by index. Or maybe there’s a better way to do this altogether.

      this.thumbs // remove navigation thumbnail — no fade
      .removeClass(‘current’)
      .eq(index) // get current index
      .addClass(‘current’); // add current class to complete process

      var index = this.getCurrentIndex() + 1;
      if (index == 12 ||
      index == 13 ||
      index == 168 ||
      index == 169 ||
      index == 170 ||
      index == 171 ||
      index == 172 ||
      index == 193 ||
      index == 194 ||
      index == 195 ||
      index == 196 ||
      index == 197 ||
      index == 198 ||
      index == 199 ||
      index == 200 ||
      index == 201 ||
      index == 202
      ) {
      opt.width= 788;
      wrapper
      .width(opt.width);
      }else{
      opt.width= 405;
      wrapper
      .width(opt.width);
      }

Leave a Reply

Your email address will not be published. Required fields are marked *

Deals

Iconfinder Coupon Code and Review

Iconfinder offers over 1.5 million beautiful icons for creative professionals to use in websites, apps, and printed publications. Whatever your project, you’re sure to find an icon or icon…

WP Engine Coupon

Considered by many to be the best managed hosting for WordPress out there, WP Engine offers superior technology and customer support in order to keep your WordPress sites secure…

InMotion Hosting Coupon Code

InMotion Hosting has been a top rated CNET hosting company for over 14 years so you know you’ll be getting good service and won’t be risking your hosting company…

SiteGround Coupon: 60% OFF

SiteGround offers a number of hosting solutions and services for including shared hosting, cloud hosting, dedicated servers, reseller hosting, enterprise hosting, and WordPress and Joomla specific hosting.