Minimalistic Slideshow Gallery with jQuery

In today’s tutorial we will create a simple and beautiful slideshow gallery that can be easily integrated in your web site. The idea is to have a container with our slideshow and the options to view a grid of thumbnails, pause the slideshow, and navigate through the pictures. The thumbnail grid will […]

View demoDownload source

In today’s tutorial we will create a simple and beautiful slideshow gallery that can be easily integrated in your web site. The idea is to have a container with our slideshow and the options to view a grid of thumbnails, pause the slideshow, and navigate through the pictures. The thumbnail grid will slide out from the top and allow the user to navigate through a set of thumbnails.

So, let’s start!

The Markup

The main HTML structure will consist of the main slideshow wrapper that contains a container for the full view image (msg_wrapper) and one for the thumbnails (msg_thumbs):

<div id="msg_slideshow" class="msg_slideshow">
	<div id="msg_wrapper" class="msg_wrapper"></div>
	<div id="msg_controls" class="msg_controls">
		<a href="#" id="msg_grid" class="msg_grid"></a>
		<a href="#" id="msg_prev" class="msg_prev"></a>
		<a href="#" id="msg_pause_play" class="msg_pause"></a>
		<a href="#" id="msg_next" class="msg_next"></a>
	</div>
	<div id="msg_thumbs" class="msg_thumbs">
		<div class="msg_thumb_wrapper">
			<a href="#">
				<img src="images/thumbs/1.jpg" alt="images/1.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/2.jpg" alt="images/2.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/3.jpg" alt="images/3.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/4.jpg" alt="images/4.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/5.jpg" alt="images/5.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/6.jpg" alt="images/6.jpg"/>
			</a>
		</div>
		<div class="msg_thumb_wrapper" style="display:none;">
			<a href="#">
				<img src="images/thumbs/1.jpg" alt="images/7.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/2.jpg" alt="images/8.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/3.jpg" alt="images/9.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/4.jpg" alt="images/10.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/5.jpg" alt="images/11.jpg"/>
			</a>
			<a href="#">
				<img src="images/thumbs/6.jpg" alt="images/12.jpg"/>
			</a>
		</div>
		<a href="#" id="msg_thumb_next" class="msg_thumb_next"></a>
		<a href="#" id="msg_thumb_prev" class="msg_thumb_prev"></a>
		<a href="#" id="msg_thumb_close" class="msg_thumb_close"></a>
		<span class="msg_loading"></span>
	</div>
</div>

The alt attribute of the thumbnails will contain the path the full view image.
The class names are getting the prefix “msg” so that the style does not interfere with anything else in your web site.
So, let’s take a look at the style.

The CSS

First, we will define the style for the main wrapper:

.msg_slideshow{
	width:400px;
	height:400px;
	padding:10px;
	position:relative;
	overflow:hidden;
	background:#101010 url(../icons/loading.gif) no-repeat center center;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
}

By setting the loading GIF to be the background image we are performing a small trick: while we are waiting for the next picture to show, our wrapper will be empty and show the loader. When the next image gets loaded it will simply hide the loader.

We will remove borders and outlines from the link elements:

.msg_slideshow a{
	outline:none;
}
.msg_slideshow a img{
	border:none;
}

In order to center the full image in the container, both, vertically and horizontally, we need to add another wrapper around. That wrapper will be displayed as a table cell. Adding the vertical-align:middle property will center the image.

.msg_wrapper{
	width:400px;
	height:400px;
	position:relative;
	margin:0;
	padding:0;
	display:table-cell;
	text-align:center;
	vertical-align:middle;
	overflow:hidden;
}
.msg_wrapper img{
	display: inline-block!important;
	vertical-align:middle;
	-moz-box-shadow:0px 0px 10px #000;
	-webkit-box-shadow:0px 0px 10px #000;
	box-shadow:0px 0px 10px #000;
}

The display property in the image style will make sure that our image does not become display:block because of the fadeIn we will use in our jQuery function. Since we want to keep our image centered horizontally, we need to keep is as an inline (-block) element.

The control element will have the following style:

.msg_controls{
	position:absolute;
	bottom:15px;
	right:-110px;
	width:104px;
	height:26px;
	z-index: 20;
	-moz-border-radius:5px;
	-webkit-border-radius:5px;
	border-radius:5px;
	background-color:#000;
	opacity:0.8;
}

The common style for all the control elements will be as follows:

.msg_controls a{
	float:left;
	background-color:#000;
	width:20px;
	height:20px;
	margin:3px 3px;
	opacity:0.5;
	background-repeat:no-repeat;
	background-position: center center;
}
.msg_controls a:hover{
	opacity:1.0;
}

The style for each icon:

.msg_controls a.msg_grid{
	background-image:url(../icons/grid.png);
}
.msg_controls a.msg_prev{
	background-image:url(../icons/prev.png);
}
.msg_controls a.msg_next{
	background-image:url(../icons/next.png);
}
.msg_controls a.msg_pause{
	background-image:url(../icons/pause.png);
}
.msg_controls a.msg_play{
	background-image:url(../icons/play.png);
}

The thumbs container will slide in from the top, so we will position it absolutely and hide it initially by setting the top to -230px:

.msg_thumbs{
	background:#000;
	position:absolute;
	width:250px;
	height:166px;
	top:-230px;
	left:50%;
	padding:30px;
	margin:0 0 0 -155px;
	-moz-border-radius:0px 0px 10px 10px;
	-webkit-border-bottom-left-radius:10px;
	-webkit-border-bottom-right-radius:10px;
	border-bottom-left-radius:10px;
	border-bottom-right-radius:10px;
	-moz-box-shadow:1px 1px 5px #000;
	-webkit-box-shadow:1px 1px 5px #000;
	box-shadow:1px 1px 5px #000;
	opacity:0.9;
	overflow:hidden;
}

With a left of 50% and a left margin of minus half of its width, we can center the absolute element horizontally.

The wrapper containing the thumbnails will have the following style:

.msg_thumb_wrapper{
	position:absolute;
	width:250px;
	height:166px;
	top:30px;
	left:30px;
	z-index:30;
}

The style of the thumbnails will be as follows:

.msg_thumb_wrapper a{
	display:block;
	width:75px;
	height:75px;
	float:left;
	margin:4px;
	opacity:0.8;
}

When we hover the thumbnail we will set the opacity to 1.0, but that we will animate in our jQuery function for a nice effect.

The style for the navigation controls:

.msg_thumbs a.msg_thumb_next,
.msg_thumbs a.msg_thumb_prev{
	width:18px;
	height:20px;
	background-repeat:no-repeat;
	background-position: center center;
	position:absolute;
	top:50%;
	margin-top:-10px;
	opacity:0.5;
}
.msg_thumbs a.msg_thumb_next:hover,
.msg_thumbs a.msg_thumb_prev:hover{
	opacity:1.0;
}
.msg_thumbs a.msg_thumb_next{
	background-image:url(../icons/next_thumb.png);
	right:5px;
}
.msg_thumbs a.msg_thumb_prev{
	background-image:url(../icons/prev_thumb.png);
	left:5px;
}

The little element for sliding back the grid view:

.msg_thumbs a.msg_thumb_close{
	position:absolute;
	bottom:0px;
	width:50px;
	left:50%;
	margin:0 0 0 -25px;
	background:#202020 url(../icons/up.png) no-repeat center center;
	height:16px;
	opacity:0.7;
	-moz-border-radius:5px 5px 0 0;
	-webkit-border-top-left-radius:5px;
	-webkit-border-top-right-radius:5px;
	border-top-left-radius:5px;
	border-top-right-radius:5px;
}

We are adding some border radius to the top right and top left corners. When we hover, we will make it opaque:

.msg_thumbs a.msg_thumb_close:hover{
	opacity:1.0;
}

And finally, the loading element for the grid view which we center horizontally and vertically with our 50% method:

.msg_loading{
	position:absolute;
	background:transparent url(../icons/loading.gif) no-repeat center center;
	top:50%;
	left:50%;
	width:50px;
	height:50px;
	margin:-25px 0 0 -25px;
	z-index:25;
	display:none;
}

And that’s all the style. Now, let’s add some magic!

The JavaScript

First, we will define some variables:

  • interval: time between the display of images
  • playtime: the timeout for the setInterval function
  • current: number to control the current image
  • current_thumb: the index of the current thumb wrapper
  • nmb_thumb_wrappers: total number of thumb wrappers
  • nmb_images_wrapper: the number of images inside of each wrapper
var interval			= 4000;
var playtime;
var current 			= 0;
var current_thumb 		= 0;
var nmb_thumb_wrappers	= $('#msg_thumbs .msg_thumb_wrapper').length;
var nmb_images_wrapper  = 6;

We start the slideshow:

play();

When we hover over the main container, we will make the controls slide in from the right:

slideshowMouseEvent();
function slideshowMouseEvent(){
	$('#msg_slideshow').unbind('mouseenter')
					   .bind('mouseenter',showControls)
					   .andSelf()
					   .unbind('mouseleave')
					   .bind('mouseleave',hideControls);
	}

When we click on the grid icon in the controls we will show the thumbnails view, pause the slideshow, and hides the control:

$('#msg_grid').bind('click',function(e){
	hideControls();
	$('#msg_slideshow').unbind('mouseenter').unbind('mouseleave');
	pause();
	$('#msg_thumbs').stop().animate({'top':'0px'},500);
	e.preventDefault();
});

Clicking on the icon to hide the thumbnails view will again show the controls:

$('#msg_thumb_close').bind('click',function(e){
	showControls();
	slideshowMouseEvent();
	$('#msg_thumbs').stop().animate({'top':'-230px'},500);
	e.preventDefault();
});

Next, we define what happens when we click pause or play. Besides changing the class, we will call the pause() or play() function:

$('#msg_pause_play').bind('click',function(e){
	var $this = $(this);
	if($this.hasClass('msg_play'))
		play();
	else
		pause();
	e.preventDefault();
});

Clicking on “next” or “previous” control will pause our slideshow and show the respective image:

$('#msg_next').bind('click',function(e){
	pause();
	next();
	e.preventDefault();
});
$('#msg_prev').bind('click',function(e){
	pause();
	prev();
	e.preventDefault();
});

Next, we define the functions for showing and hiding the controls. By setting the right value, we will make it slide. Remember, that we set an initial negative value in the CSS.

function showControls(){
	$('#msg_controls').stop().animate({'right':'15px'},500);
}
function hideControls(){
	$('#msg_controls').stop().animate({'right':'-110px'},500);
}

The play() function which makes the slideshow go:

function play(){
	next();
	$('#msg_pause_play').addClass('msg_pause').removeClass('msg_play');
	playtime = setInterval(next,interval)
}

The function for pausing the slideshow. We change again the class and clear the timeout:

function pause(){
	$('#msg_pause_play').addClass('msg_play').removeClass('msg_pause');
	clearTimeout(playtime);
}

The next two function will show the next or previous image:

function next(){
	++current;
	showImage('r');
}
function prev(){
	--current;
	showImage('l');
}

The next function is for showing the image. We also call alternateThumbs(), which will always change the grid to display the view where the current image is located.

function showImage(dir){
	/**
	* the thumbs wrapper being shown, is always 
	* the one containing the current image
	*/
	alternateThumbs();
	
	/**
	* the thumb that will be displayed in full mode
	*/
	var $thumb = $('#msg_thumbs .msg_thumb_wrapper:nth-child('+current_thumb+')')
				.find('a:nth-child('+ parseInt(current - nmb_images_wrapper*(current_thumb -1)) +')')
				.find('img');
	if($thumb.length){
		var source = $thumb.attr('alt');
		var $currentImage = $('#msg_wrapper').find('img');
		if($currentImage.length){
			$currentImage.fadeOut(function(){
				$(this).remove();
				$('<img />').load(function(){
					var $image = $(this);
					resize($image);
					$image.hide();
					$('#msg_wrapper').empty().append($image.fadeIn());
				}).attr('src',source);
			});
		}
		else{
			$('<img />').load(function(){
					var $image = $(this);
					resize($image);
					$image.hide();
					$('#msg_wrapper').empty().append($image.fadeIn());
			}).attr('src',source);
		}
				
	}
	else{ //this is actually not necessary since we have a circular slideshow
		if(dir == 'r')
			--current;
		else if(dir == 'l')
			++current;	
		alternateThumbs();
		return;
	}
}

The thumbs wrapper being shown is always the one containing the current image. So, we define a function that controls this:

function alternateThumbs(){
	$('#msg_thumbs').find('.msg_thumb_wrapper:nth-child('+current_thumb+')')
					.hide();
	current_thumb = Math.ceil(current/nmb_images_wrapper);
	/**
	* if we reach the end, start from the beggining
	*/
	if(current_thumb > nmb_thumb_wrappers){
		current_thumb 	= 1;
		current 		= 1;
	}
	/**
	* if we are at the beggining, go to the end
	*/
	else if(current_thumb == 0){
		current_thumb 	= nmb_thumb_wrappers;
		current 		= current_thumb*nmb_images_wrapper;
	}

	$('#msg_thumbs').find('.msg_thumb_wrapper:nth-child('+current_thumb+')')
					.show();
}

Next, we define what happens when we navigate through the thumbs:

$('#msg_thumb_next').bind('click',function(e){
	next_thumb();
	e.preventDefault();
});
$('#msg_thumb_prev').bind('click',function(e){
	prev_thumb();
	e.preventDefault();
});
function next_thumb(){
	var $next_wrapper = $('#msg_thumbs').find('.msg_thumb_wrapper:nth-child('+parseInt(current_thumb+1)+')');
	if($next_wrapper.length){
		$('#msg_thumbs').find('.msg_thumb_wrapper:nth-child('+current_thumb+')')
						.fadeOut(function(){
							++current_thumb;
							$next_wrapper.fadeIn();
						});
	}
}
function prev_thumb(){
	var $prev_wrapper = $('#msg_thumbs').find('.msg_thumb_wrapper:nth-child('+parseInt(current_thumb-1)+')');
	if($prev_wrapper.length){
		$('#msg_thumbs').find('.msg_thumb_wrapper:nth-child('+current_thumb+')')
						.fadeOut(function(){
							--current_thumb;
							$prev_wrapper.fadeIn();
						});
	}
}

Clicking on a thumbnail will load the respective image:

$('#msg_thumbs .msg_thumb_wrapper > a').bind('click',function(e){
	var $this 		= $(this);
	$('#msg_thumb_close').trigger('click');
	var idx			= $this.index();
	var p_idx		= $this.parent().index();
	current			= parseInt(p_idx*nmb_images_wrapper + idx + 1);
	showImage();
	e.preventDefault();
}).bind('mouseenter',function(){
	var $this 		= $(this);
	$this.stop().animate({'opacity':1});
}).bind('mouseleave',function(){
	var $this 		= $(this);
	$this.stop().animate({'opacity':0.5});
});

And finally, our resize function that fits the image inside of our container, which we defined to be 400×400 pixel:

function resize($image){
	var theImage 	= new Image();
	theImage.src 	= $image.attr("src");
	var imgwidth 	= theImage.width;
	var imgheight 	= theImage.height;

	var containerwidth  = 400;
	var containerheight = 400;

	if(imgwidth	> containerwidth){
		var newwidth = containerwidth;
		var ratio = imgwidth / containerwidth;
		var newheight = imgheight / ratio;
		if(newheight > containerheight){
			var newnewheight = containerheight;
			var newratio = newheight/containerheight;
			var newnewwidth =newwidth/newratio;
			theImage.width = newnewwidth;
			theImage.height= newnewheight;
		}
		else{
			theImage.width = newwidth;
			theImage.height= newheight;
		}
	}
	else if(imgheight > containerheight){
		var newheight = containerheight;
		var ratio = imgheight / containerheight;
		var newwidth = imgwidth / ratio;
		if(newwidth > containerwidth){
			var newnewwidth = containerwidth;
			var newratio = newwidth/containerwidth;
			var newnewheight =newheight/newratio;
			theImage.height = newnewheight;
			theImage.width= newnewwidth;
		}
		else{
			theImage.width = newwidth;
			theImage.height= newheight;
		}
	}
	$image.css({
		'width'	:theImage.width,
		'height':theImage.height
	});
}

And that’s it! We hope you enjoyed this tutorial and find our little slideshow useful!

View demoDownload source

Previous:
Next:

Tagged with:

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

View all contributions by

Website: http://www.codrops.com

Related Articles

Receive our bi-weekly Collective or official newsletter right in your inbox.

Which newsletter would you like to receive?

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 66

Comments are closed.
  1. 2

    This is very well done but I still prefer to have thumbnails generated automatically and (future improvement) maybe have an option to load images from Flickr or a folder.
    Well DONE!!

  2. 3

    The design is actually pretty nice on this. Very well written tutorial!

  3. 4

    Very nice, any chance of added the ability to add a comment to each pic that slides up as the pic is shown?

  4. 5

    Great !!
    Wonderfull slideshow and use of jquery but :

    – Why you dont use UL with LI to display image (I dont know why but i dont like many following link : A HREF=’#’) ?

    – I Think Your demo is ….too dark

    Jireck

  5. 6

    Hi Jireck! You are right, I am link obsessed, someone should slap me! 🙂 I will keep that in mind for the next tuts. In the meantime, here is version with list elements and in light color:
    DEMO
    ZIP
    What do you say?
    Cheers, ML

  6. 9

    wow Mary Lou make different versi but its cool
    its cool and thats cool = all cool
    WOW!!!

  7. 11

    This gallery is fantastic – have shown it to a few here at work – they just loved it too 🙂 Thanks for this tutorial.

  8. 13

    Hi Mary Lou

    The demo is really Nice ….

    I think it’s more clean to do with UL LI…

    I will check code (i DL your zip)

    thanks

    Jireck
    PS : Reactivity increase !!! 😉

  9. 15

    Loved the gallery just what I am looking for. I need a little help though. If i try to put the gallery twice in one page, the one load perfectly the other, just has the loading sign, any idea why? Since I would like to put 3 on one page.

  10. 17

    Thank you for sharing admin.demo been nice greetings and best regards

  11. 20

    Thank you very much
    I am using it and it looks amazing.
    Code explanation made it easy for me to customize it for my site.

  12. 22

    Hello! It’s really fantastic gallery! But I have the question – script works with only 12 images and I can’t find how expand this size. There are about 100 images in my folder and I’d like to show they all.

Comments are closed.