Slider Gallery with jQuery

This tutorial is about creating a creative gallery with a slider for the thumbnails. The idea is to have an expanding thumbnails area which opens once an album is chosen. […]

This tutorial is about creating a creative gallery with a slider for the thumbnails. The idea is to have an expanding thumbnails area which opens once an album is chosen. The thumbnails will scroll to the end and move back to the first image. The user can scroll through the thumbnails by using the slider controls. When a thumbnail is clicked, it moves to the center and the full image preview opens. Navigating though the images will make them slide in and out from the sides, moving the underlying thumbnails container. When the preview is closed, the full image will fade back to the thumbnail.

For this gallery we will be using the jQuery UI library and the jQuery Easing Plugin.

The beautiful photos are by beyrouth and his Flickr photostream can be found here.

So, let’s get started!

The Markup

We will have one main container, where we will put all our elements:

<div id="fp_gallery" class="fp_gallery">
...
</div>

Inside of this main container, we will first add a background image and a div that will contain a background pattern:

<img src="images/bgimg.jpg" class="fp_bgImage" />
<div class="fp_bgPattern"></div>

The idea is to use a very small (375px times 500px) and stretch it over the screen and set the opacity very low to make it look blurry. Then we will add a pattern on top, as well with a low opacity, so that the images shines through. You can try and add other patterns, it creates a very unique effect.

Now we will add the headings and the menu with the album names:

<h1>Fashion Photography</h1>
<h2>by parisbeyrouth</h2>

<ul id="fp_galleryList" class="fp_galleryList">
	<li>Paris</li>
	<li>New York</li>
	<li>Los Angeles</li>
	<li>Milano</li>
</ul>

Then we will add the thumbnail container which will be hidden initially. Inside of the container we will have a wrapper with the single album containers inside. We have four albums, so we add four containers:

<div id="fp_thumbContainer">
	<div id="fp_thumbScroller">
		<div class="container">
			<div class="content">
				<div>
					<a href="#">
						<img src="images/album1/thumbs/1.jpg" alt="images/album1/1.jpg" class="thumb" />
					</a>
				</div>
			</div>
			<div class="content">
				<div>
					<a href="#">
						<img src="images/album1/thumbs/2.jpg" alt="images/album1/2.jpg" class="thumb" />
					</a>
				</div>
			</div>
			...
		</div>
		<div class="container">
			...
		</div>
		<div class="container">
			...
		</div>
		<div class="container">
			...
		</div>
	</div>
</div>

The images will carry the path to the full image in their alt attribute.

The slider will have the following structure:

<div id="fp_scrollWrapper" class="fp_scrollWrapper">
	<span id="fp_prev_thumb" class="fp_prev_thumb"></span>
	<div id="slider" class="slider"></div>
	<span id="fp_next_thumb" class="fp_next_thumb"></span>
</div>

And finally, we will add all the elements relevant to the full image preview:

<div id="fp_overlay" class="fp_overlay"></div>
<div id="fp_loading" class="fp_loading"></div>
<div id="fp_next" class="fp_next"></div>
<div id="fp_prev" class="fp_prev"></div>
<div id="fp_close" class="fp_close">Close preview</div>

Let’s take a look at the style.

The CSS

First, we are going to reset the style and add some general body styling properties:

*{
	margin:0;
	padding:0;
}
body {
	margin:0;
	padding:0;
	background:#000;
	text-align:center;
	color:#fff;
	font-family:Arial, Helvetica, sans-serif;
	overflow:hidden;
}

For the pattern and the image in the background we will set the following styles:

.fp_bgPattern{
	position:fixed;
	top:0px;
	left:0px;
	width:100%;
	height:100%;
	background:transparent url(../images/greyscale_natural_grunge3.jpg) repeat bottom left;
	opacity:0.3;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);
}
img.fp_bgImage{
	position:fixed;
	top:0px;
	left:0px;
	width:100%;
	opacity:0.2;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
}

Both of the elements will have a fixed position and a very low opacity, in order to get the effect I was talking about before.

Now, we will style the headings:

h1{
	font-weight:normal;
	margin:40px 0px 10px 0px;
	text-transform:uppercase;
}
h2{
	font-weight:normal;
	font-size:22px;
	color:#FFED2F;
	margin-bottom:50px;
}

We generally don’t want that any a element has an outline when we click on it:

a{
	outline:none;
}

But be careful with this property though. If you want tabbing through links to be possible then you should never define the outline as none.

The gallery album list will be styled as follows:

ul.fp_galleryList{
	list-style:none;
	position:relative;
}
ul.fp_galleryList li{
	display:inline;
	margin:0px 30px;
	text-transform:uppercase;
	cursor:pointer;
	font-size:14px;
	text-shadow:0px 0px 1px #fff;
}
ul.fp_galleryList li.current{
	color:#FFED2F;
}
ul.fp_galleryList li.current:hover{
	border:none;
}
ul.fp_galleryList li:hover{
	border-bottom:1px solid #fff;
}

A white even text shadow around white text will make the font look very smooth in Google Chrome.

The thumb container will not be visible initially since we set it’s height to 0 pixel. In the JavaScript we will “open” it by animating its height to 240 pixels. Note that this is the main wrapper for the thumbnails container. We set the width to 100% of the screen while we don’t allow any overflow. Just the elements inside will have a width that will allow scrolling:

#fp_thumbContainer{
	position:relative;
	overflow:hidden;
	width:100%;
	margin:50px 0 30px 0;
	height:0px; /*240px to show*/
	background-color:#111;
	-moz-box-shadow:0px 0px 10px #000 inset;
	-webkit-box-shadow:0px 0px 10px #000 inset;
	box-shadow:0px 0px 10px #000 inset;
}

The thumbScroller is going to be the wrapper that will be scrolled:

#fp_thumbScroller{
	position:relative;
	overflow:hidden;	
}

The container element represents an album and we will define the width of this container based on the content inside. That will be done dynamically in the JavaScript:

#fp_thumbScroller .container{
	position:relative;
	float:left;
	display:none;
}
#fp_thumbScroller .content{
	float:left;
	margin-top:17px;
}
#fp_thumbScroller .content div{
	margin:0px 5px;
	height:100%;
}

To the image we will add some white rounded border and a box shadow:

#fp_thumbScroller img{
	border:3px solid #fff;
	height:200px;
	-moz-box-shadow:1px 1px 3px #000;
	-webkit-box-shadow:1px 1px 3px #000;
	box-shadow:1px 1px 3px #000;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
}
#fp_thumbScroller a{
	padding:1px;
}

Before we look into the style of the slider, we will define the looks of the full preview elements. The black overlay will have the following style:

.fp_overlay{
	display:none;
	position:fixed;
	top:0px;
	left:0px;
	right:0px;
	bottom:0px;
	z-index:10;
	background:#000;
	opacity:0.8;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=80);
}

The loading div will be centered relatively to the whole page, so we do the 50%/negative margin trick:

.fp_loading{
	display:none;
	position:fixed;
	top:50%;
	left:50%;
	margin:-35px 0px 0px -35px;
	background:#fff url(../images/loader.gif) no-repeat center center;
	width:70px;
	height:70px;
	z-index:9999;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
	-moz-box-shadow:1px 1px 3px #000;
	-webkit-box-shadow:1px 1px 3px #000;
	box-shadow:1px 1px 3px #000;
	opacity:0.7;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}

The navigation elements and the close element will have the following common style:

.fp_next,
.fp_prev,
.fp_close{
	width:50px;
	height:50px;
	position:fixed;
	bottom:50%;
	margin-top:-25px;
	cursor:pointer;
	opacity:0.7;
	z-index:1000;
	-moz-box-shadow:0px 0px 3px #000;
	-webkit-box-shadow:0px 0px 3px #000;
	box-shadow:0px 0px 3px #000;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}
.fp_next:hover,
.fp_prev:hover,
.fp_close:hover
{
	opacity:0.9;
}

And they will have the following individual style:

.fp_next{
	background:#fff url(../images/next.png) no-repeat center center;
	right:-50px; /*10 to show*/
}
.fp_prev{
	background:#fff url(../images/prev.png) no-repeat center center;
	left:-50px; /*10 to show*/
}
.fp_close{
	display:none;
	width:170px;
	text-align:center;
	padding-left:10px;
	text-transform:uppercase;
	line-height:50px;
	top:10px;
	right:10px;
	margin-top:0px;
	background:#fff url(../images/close.png) no-repeat 10px 50%;
	color:#000;
}

Now we will define the scrollWrapper that contains the slider and the slider navigation:

.fp_scrollWrapper{
	display:none;
	width:300px;
	padding:10px 45px;
	height:12px;
	position:relative;
	margin:30px auto;
	background:#111;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
}

We also need to redefine some css properties of the jQuery UI elments that get defined in the stylesheets that come with the library. So make sure you include this CSS after the inclusion of the jQuery UI styles.

The following is the slider bar:

.ui-widget-content{
	height:12px;
	background-color:#353535;
	position:relative;
	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;
}

And this is the little handle:

.ui-slider-horizontal .ui-slider-handle{
	margin-top:5px;
	z-index:1;
	outline:none;
	cursor:pointer;
	border:none;
	width:15px;
	height:12px;
	background: #9b9b9b;
	margin-left:-7px;
}

This class also gets applied to the handle element, and we don’t want any background image for that:

.ui-state-default {
	background-image:none;
}

The navigation elements for the slider are styled as follows:

.fp_prev_thumb,
.fp_next_thumb{
	background:transparent url(../images/nav.png) no-repeat top left;
	position:absolute;
	top:8px;
	width:15px;
	height:17px;
	cursor:pointer;
}
.fp_prev_thumb:hover{
	background-position:left top;
}
.fp_next_thumb:hover{
	background-position:right top;
}
.fp_prev_thumb{
	left:10px;
	background-position:left bottom;
}
.fp_next_thumb{
	right:10px;
	background-position:right bottom;
}

We will use one background image that contains the two navigation arrows with an active and inactive state.

And finally, we will style the large preview image. The positioning of the image will be set in the JavaScript:

img.fp_preview{
	position:fixed;
	z-index:999;
	border:3px solid #fff;
	-moz-box-shadow:1px 1px 3px #000;
	-webkit-box-shadow:1px 1px 3px #000;
	box-shadow:1px 1px 3px #000;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
	opacity:0;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);	
}

And that’s all the style! Now, lets create some awesome effects!

The JavaScript

For the effects we will be using some easing so don’t forget to include the jQuery easing plugin.
In our jQuery function we will start by defining some variables:

//caching
//the main wrapper of the gallery
var $fp_gallery			= $('#fp_gallery')
//the overlay when the large image is displayed
var $fp_overlay			= $('#fp_overlay');
//image loading status
var $fp_loading			= $('#fp_loading');
//the next and previous buttons
var $fp_next			= $('#fp_next');
var $fp_prev			= $('#fp_prev');
//the close button
var $fp_close			= $('#fp_close');
//the main container for the thumbs structure
var $fp_thumbContainer 	= $('#fp_thumbContainer');
//wrapper of jquery ui slider
var $fp_scrollWrapper	= $('#fp_scrollWrapper');
//wrapper of each content div, where each image is
var $fp_content_wrapper;
//total number of images
var nmb_images=0;
//which gallery is clicked (index)
var gallery_idx=-1;
//scroller wrapper
var $fp_thumbScroller	= $('#fp_thumbScroller');
//jquery ui slider
var $slider				= $('#slider');
//the links of the galleries (the cities)
var $fp_galleries		= $('#fp_galleryList > li');
//current image being viewed
var current				= 0;
//some control flags:
//prevent fast clicks on next and previous
var photo_nav			= true;

We bind a click event to the galleries / album items. This item index is stored to keep track of which gallery is currently opened. If one gallery was opened already, we close it (by sliding it in) before opening this gallery.

//User clicks on an album / gallery;
$fp_galleries.bind('click',function(){
	$fp_galleries.removeClass('current');
	var $gallery 		= $(this);
	$gallery.addClass('current');
	var gallery_index 	= $gallery.index();
	if(gallery_idx == gallery_index) return;
	gallery_idx			= gallery_index;
	//close the gallery and slider if opened
	if($fp_thumbContainer.data('opened')==true){
		$fp_scrollWrapper.fadeOut();
		$fp_thumbContainer.stop()
						  .animate({'height':'0px'},200,function(){
							openGallery($gallery);
						  });
	}				  
	else
		openGallery($gallery);
});

This function opens a gallery. We need to calculate the total width of the content wrapper by summing the widths of each image area. We also need to calculate the padding, both left and right, since we want to center the first and last image on the screen, when we scroll all left and right.
The jQuery UI slider is initialized, and is set to slide as much as we can scroll the wrapper.
To make all the images slide in initially, we scroll the wrapper to the right before the gallery is opened, and after opening it, we animate the scrollLeft to 0px.
We also bind a click event to each one of the images elements, which will center the clicked image, and display it in full size.

//opens a gallery after clicking on an album / gallery
function openGallery($gallery){
	//current gets reset
	current				= 0;				  
	//wrapper of each content div, where each image is
	$fp_content_wrapper = $fp_thumbContainer.find('.container:nth-child('+parseInt(gallery_idx+1)+')');
	//hide all the other gallerie's thumbs wrappers
	$fp_thumbContainer.find('.container').not($fp_content_wrapper).hide();
	//and show this one
	$fp_content_wrapper.show();
	//total number of images
	nmb_images			= $fp_content_wrapper.children('div').length;
	//calculate width,
	//padding left 
	//and padding right for content wrapper
	var w_width 	= 0;
	var padding_l	= 0;
	var padding_r	= 0;
	//center of screen
	var center		= $(window).width()/2;
	var one_divs_w  = 0;
	/*
	Note:
	the padding left is the center minus half of the width of the first content div
	the padding right is the center minus half of the width of the last content div
	*/
	$fp_content_wrapper.children('div').each(function(i){
		var $div 		= $(this);
		var div_width	= $div.width(); 
		w_width			+=div_width;
		//if first one, lets calculate the padding left
		if(i==0)
			padding_l = center - (div_width/2);
		//if last one, lets calculate the padding right
		if(i==(nmb_images-1)){
			padding_r = center - (div_width/2);
			one_divs_w= div_width;
		}	
	}).end().css({
		'width'				: w_width + 'px',
		'padding-left' 		: padding_l + 'px',
		'padding-right' 	: padding_r + 'px'
	});
	//scroll all left;
	$fp_thumbScroller.scrollLeft(w_width);
	//initialize the slider
	$slider.slider('destroy').slider({
		orientation	: 'horizontal',
		max			: w_width -one_divs_w,//total width minus one content div width
		min			: 0,
		value		: 0,
		slide		: function(event, ui) {
			$fp_thumbScroller.scrollLeft(ui.value);
		},
		stop: function(event, ui) {
			//when we stop sliding 
			//we may want that the closest picture to the center 
			//of the window stays centered. Uncomment the following line
			//if you want that behavior
			checkClosest();
		}
	});
	//open the gallery and show the slider
	$fp_thumbContainer.animate({'height':'240px'},200,function(){
		$(this).data('opened',true);
		$fp_scrollWrapper.fadeIn();
	});
	
	//scroll all right;
	$fp_thumbScroller.stop()
					 .animate({'scrollLeft':'0px'},2000,'easeInOutExpo');

	//User clicks on a content div (image)
	$fp_content_wrapper.find('.content')
					 .bind('click',function(e){
		var $current 	= $(this);
		//track the current one
		current			= $current.index();
		//center and show this image
		//the second parameter set to true means we want to 
		//display the picture after the image is centered on the screen
		centerImage($current,true,600);
		e.preventDefault();
	});
}

When the wrapper is scrolling, we also want the slider to scroll:

//while the gallery scrolls we want that the slider scrolls as well
$fp_thumbScroller.scroll(function(){
	$slider.slider('value',parseInt($fp_thumbScroller.scrollLeft(),10));
});

These are the click events for both, next and previous buttons, when the user sees the images in full size. The function “navigate” is called either with “1” for next or “0” for previous

//User clicks next button (preview mode)
$fp_next.bind('click',function(){
	if(photo_nav){
		photo_nav = false;
		navigate(1);
	}	
});

//User clicks previous button (preview mode)
$fp_prev.bind('click',function(){
	if(photo_nav){
		photo_nav = false;
		navigate(0);
	}	
});

Besides sliding the thumbs wrapper, we also want the ability to slide one at a time. The following are the click events for the buttons that take that action.

//User clicks next button (thumbs)
$('#fp_next_thumb').click(function(){
	slideThumb(1);
});

//User clicks previous button (thumbs)
$('#fp_prev_thumb').click(function(){
	slideThumb(0);
});

The centerImage function is used to scroll the wrapper until the respective image is centered on the screen. If “open” is true, then it also shows the thumb in full size, by calling the enlarge function.

//centers an image and opens it if open is true
function centerImage($obj,open,speed){
	//the offset left of the element
	var obj_left 			= $obj.offset().left;
	//the center of the element is its offset left plus 
	//half of its width
	var obj_center 			= obj_left + ($obj.width()/2);
	//the center of the window
	var center				= $(window).width()/2;
	//how much the scroller has scrolled already
	var currentScrollLeft 	= parseFloat($fp_thumbScroller.scrollLeft(),10);
	//so we know that in order to center the image,
	//we must scroll the center of the image minus the center of the screen,
	//and add whatever we have scrolled already
	var move 				= currentScrollLeft + (obj_center - center);
	if(move != $fp_thumbScroller.scrollLeft()) //try 'easeInOutExpo'
		$fp_thumbScroller.stop()
						 .animate({scrollLeft: move}, speed,function(){
			if(open)
				enlarge($obj);
		});
	else if(open)
		enlarge($obj);
}

To enlarge the thumb, we load the respective full image, place it on top of the thumb, and then animate it to the maximum we can get, based on the current windows size. After the image is enlarged, we display the close, next and previous buttons.

function enlarge($obj){
	//the image element
	var $thumb = $obj.find('img');
	//show loading image
	$fp_loading.show();
	//preload large image
	$('').load(function(){
		var $large_img 	= $(this);
		
		//confirm there's no other large one
		$('#fp_preview').remove();
		
		$large_img.addClass('fp_preview');
		//now let's position this image on the top of the thumb
		//we append this image to the fp_gallery div
		var obj_offset 	= $obj.offset();
		$large_img.css({
			'width'	: $thumb.width() + 'px',
			'height': $thumb.height() + 'px',
			'top'	: obj_offset.top + 'px',
			'left'	: obj_offset.left + 5 + 'px'//5 of margin
		}).appendTo($fp_gallery);
		//getFinalValues gives us the maximum possible width and height
		//for the large image based on the windows size.
		//those values are saved on the element using the jQuery.data()
		getFinalValues($large_img);
		var largeW 	= $large_img.data('width');
		var largeH 	= $large_img.data('height');
		//windows width, height and scroll
		var $window = $(window);
		var windowW = $window.width();
		var windowH = $window.height();
		var windowS = $window.scrollTop();
		//hide the image loading
		$fp_loading.hide();
		//show the overlay
		$fp_overlay.show();
		//now animate the large image
		$large_img.stop().animate({
			'top'		: windowH/2 -largeH/2 + windowS + 'px',
			'left'		: windowW/2 -largeW/2 + 'px',
			'width'		: largeW + 'px',
			'height'	: largeH + 'px',
			'opacity'	: 1
		},800,function(){
			//after the animation, 
			//show the next, previous and close buttons
			showPreviewFunctions();
		});
	}).attr('src',$thumb.attr('alt'));
}

Clicking the close button will make the full image animate its positions and dimensions to the same ones like the respective thumb. After that we remove the image from the document.

//User clicks close button
$fp_close.bind('click',function(){
	//windows scroll if any
	var windowS 		= $(window).scrollTop();
	//the large image being viewed
	var $large_img		= $('#fp_preview');
	//the current thumb
	var $current 		= $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
										   .find('.content:nth-child('+parseInt(current+1)+')');
	//offset values of current thumb
	var current_offset	= $current.offset();
	//the large image will animate in the direction of the center
	//after that it is removed from the DOM
	$large_img.stop().animate({
		'top'			: current_offset.top + windowS + 'px',
		'left'			: $(window).width()/2 - $current.width()/2 + 'px',
		'width'			: $current.width() + 'px',
		'height'		: $current.height() + 'px',
		'opacity'		: 0
	},800,function(){
		$(this).remove();
		//hide the overlay, and the next, previous and close buttons
	hidePreviewFunctions();
	});
});

When an image is enlarged, we can navigate to the next or previous image of the gallery. By doing it, we want the slider to scroll, so that the current thumb is always behind the image that is being displayed.
If we click the next button, the current image slides out on the left side and the next one slides in from the right side of the window. We revert this logic if we click the previous button.

//shows next or previous image
//1 is right;0 is left
function navigate(way){
	//show loading image
	$fp_loading.show();
	if(way==1){
		++current;
		var $current = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
										.find('.content:nth-child('+parseInt(current+1)+')');
		if($current.length == 0){
			--current;
			$fp_loading.hide();
			photo_nav = true;
			return;
		}
	}
	else{
		--current;
		var $current = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
										.find('.content:nth-child('+parseInt(current+1)+')');
		if($current.length == 0){
			++current;
			$fp_loading.hide();
			photo_nav = true;
			return;
		}
	}
		
	//load large image of next/previous content div
	$('').load(function(){
		$fp_loading.hide();
		var $large_img 		= $(this);
		var $fp_preview 	= $('#fp_preview');
		
		//make the current one slide left if clicking next
		//make the current one slide right if clicking previous
		var animate_to 		= -$fp_preview.width();
		var animate_from	= $(window).width();
		if(way==0){
			animate_to 		= $(window).width();
			animate_from	= -$fp_preview.width();
		}
		//now we want that the thumb (of the last image viewed) 
		//stays centered on the screen
		centerImage($current,false,1000);
		$fp_preview.stop().animate({'left':animate_to+'px'},500,function(){
			$(this).remove();
			$large_img.addClass('fp_preview');
			getFinalValues($large_img);
			var largeW 	= $large_img.data('width');
			var largeH 	= $large_img.data('height');
			var $window	= $(window);
			var windowW = $window.width();
			var windowH = $window.height();
			var windowS = $window.scrollTop();
			$large_img.css({
				'width'		: largeW+'px',
				'height'	: largeH+'px',
				'top'		: windowH/2 -largeH/2 + windowS + 'px',
				'left'		: animate_from + 'px',
				'opacity' 	: 1	
			}).appendTo($fp_gallery)
			  .stop()
			  .animate({
				'left':windowW/2 -largeW/2+'px'
			  },500,function(){photo_nav = true;});
		});
	}).attr('src',$current.find('img').attr('alt'));	
}

Given an image, the following function saves the maximum width and height that the image can have based on the windows size. It is used when we want to enlarge one image, and we need to calculate its final positions and dimensions.

function getFinalValues($image){
	var widthMargin		= 0
	var heightMargin 	= 20;
	var $window			= $(window);
	var windowH      	= $window.height()-heightMargin;
	var windowW      	= $window.width()-widthMargin;
	var theImage     	= new Image();
	theImage.src     	= $image.attr("src");
	var imgwidth     	= theImage.width;
	var imgheight    	= theImage.height;

	if((imgwidth > windowW)||(imgheight > windowH)){
		if(imgwidth > imgheight){
			var newwidth = windowW;
			var ratio = imgwidth / windowW;
			var newheight = imgheight / ratio;
			theImage.height = newheight;
			theImage.width= newwidth;
			if(newheight>windowH){
				var newnewheight = windowH;
				var newratio = newheight/windowH;
				var newnewwidth =newwidth/newratio;
				theImage.width = newnewwidth;
				theImage.height= newnewheight;
			}
		}
		else{
			var newheight = windowH;
			var ratio = imgheight / windowH;
			var newwidth = imgwidth / ratio;
			theImage.height = newheight;
			theImage.width= newwidth;
			if(newwidth>windowW){
				var newnewwidth = windowW;
				var newratio = newwidth/windowW;
				var newnewheight =newheight/newratio;
				theImage.height = newnewheight;
				theImage.width= newnewwidth;
			}
		}
	}
	$image.data('width',theImage.width);
	$image.data('height',theImage.height);
}

When we use the jQuery UI slider, we want to make sure that, when we stop sliding, the closest picture to the center of the screen gets centered. The following function takes care of that when called on the stop event of the slider.

function checkClosest(){
	var center 				= $(window).width()/2;
	var current_distance 	= 99999999;
	var idx					= 0;	
	$container				= $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')');
	$container.find('.content').each(function(i){
		var $obj 		= $(this);
		//the offset left of the element
		var obj_left 	= $obj.offset().left;
		//the center of the element is its offset left plus 
		//half of its width
		var obj_center 	= obj_left + ($obj.width()/2);
		var distance	= Math.abs(center-obj_center);
		if(distance < current_distance){
			current_distance 	= distance;
			idx					= i;
		}	
	});
	var $new_current 	= $container.find('.content:nth-child('+parseInt(idx+1)+')');
	current 			= $new_current.index();
	centerImage($new_current,false,200);
}

The slideThumb function is used when we want to scroll the thumbs one at a time. It calls the centerImage function for the next or previous element in the gallery.

//slides the scroller one picture 
//to the right or left
function slideThumb(way){
	if(way==1){
		++current;
		var $next = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
									 .find('.content:nth-child('+parseInt(current+1)+')');
		if($next.length > 0)
			centerImage($next,false,600);
		else{
			--current;
			return;
		}	
	}
	else{
		--current;
		var $prev = $fp_thumbScroller.find('.container:nth-child('+parseInt(gallery_idx+1)+')')
									 .find('.content:nth-child('+parseInt(current+1)+')');
		if($prev.length > 0)
			centerImage($prev,false,600);
		else{
			++current;
			return;
		}	
	}					
}

To give the whole thing an even nicer look, we will cufonize the headings and the close text, by adding the following lines to the header of the HTML:

<script src="js/cufon-yui.js" type="text/javascript"></script>
<script src="js/GreyscaleBasic.font.js" type="text/javascript"></script>
<script type="text/javascript">
	Cufon.replace('h1,h2,.fp_close');
</script>

You can find the "Greyscale Basic" font on Fontsquirrel.com.

And that's it! We hope you enjoyed and found this tutorial useful!!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 198

Comments are closed.
  1. but i have a question: is it possible to load a album on start page, and is it possible to outline thumbnails left instead of center? Thanks, great job!

  2. Awesome! I have one question though.

    How can I close the Thumb Gallery? Or did I just miss something in this tutorial.

  3. Great gallery!

    Does anyone know how to make the images display on the left with no big gap and also have no gap at the end? So basically just a gallery with no dead space?

    I was also wondering how do you use the gallery without having to click on the names so the gallery appears auto?

    Thanks in advance!

  4. Great job, have just found this tuto and i’ll try to use it right now…
    RUDY & LUCASAN both asked a question and din’t have the answer, i’ll be the 3rd one and hope we’ll have an answer πŸ™‚
    how can we display a default gallery the prevent the user an additional click??

    Thank you so much,
    Reda

  5. +1 i would also like to know how to load an default page! Awesome tutorials, really impressive!

    kind regards,
    Dennis

  6. Hi MaryLou. This is so Awesome! Thanks!

    How can I add a description for the images under the Zoomed photo?

    Cheers from Belize!

  7. Thank you Mary Lou ! Great post !!

    Do you know how add mousewheel and keyboard nav ?

    I’ve tried, but it’s difficult for me πŸ˜‰

    Thanks !

  8. Mary Lou, thank you so much for the tutorial! It’s very useful!

    Could I also ask how I can already load the gallery once finish loading (instead of clicking on the list)?

    I’ve tried but no luck.

    Thank you again

  9. I love this design and I would like to bring it to the next level. I connected the images to my database and now the galleries are fully dynamic.

    The only thing is when you have many galleries and images the page is slow to load even on a fast network:

    1/ Is there a way we could not preload the page but when we click the gallery name it would load the gallery instead?

    2/ Can we set a text in the middle so we can indicate the user to select a gallery and to click the thumbnail to enlarge the image. You would be amazed when I show the site that people don’t even think they can click to enlarge.

    3/ How could we add caption to the image? I saw you had another example that have the caption feature.

    Thank you and keep up the great work!

    Laurent

  10. Hi Mary Lou, great job on coding up this slider. I’m using it in a client’s project at http://gi.glamourimage.com.au/ and there’s a major issue with it loading the larger images in the gallery we’ve setup so far. Basically, the images we originally used are 800×600 which fit in the screen perfectly at 1025x768res, but on first view the preload busy indicator displays, then instead of showing the image all we get is the borders collapsing down to a 0 sized image. If we go to the next image, the same thing happens. If you go back to the previous image, then the image is actually there then, and that happens on every first load, and complete refresh, and clean cache. So first time visitor’s get no image to start off with.
    I’ve tried minifying the code, and removed stuff not needed. And even tried reducing the image sizes by 75%, and their compression from 98 to 85 to reduce the filesize, thinking it may have been a load time issue.
    I noticed your images are all about 30K, which also made me think the filesizes of our images is the problem.
    If you can shed any light, we would be most appreciative. TIA.

  11. Hi Mary Lou,

    Thank you for the awesome gallery.

    I am very new to programming and I can’t get my album 3 and album 4 to show. I have containers for all 4. Album 1 and 2 work fine, is there something I am missing besides the containers.

    Any help would be greatly appreciated. Thank you!!!!

  12. Hi – great plugin but have run into an odd problem in IE8. For some reason all the thumbnails do not show in the slider portion and instead “wrap around” to the next row. So the user thinks they’ve hit the end when actually there’s another photo. I also see this is Firefox. No such issue in Chrome nor Safari.

    Does anyone have any ideas about this? Driving me nuts!!

    Thanks.
    Rob

  13. BTW, there’s seems to be loading issue’s with timeout’s when using images other than what comes with any of Mary Lou’s Gallery’s. I’ve also noticed the images she’s using are highly compressed and of a size unsuitable for Photographer’s Portfolio’s which she is aiming them for. Other than that, her work is awesome in concept. They just need some sort of working preloader, or wait load to make sure the images are loaded.

  14. I added a preloader (UIProgressBar) using a jq Plugin which is applied on a list of img objects and calls
    * the specified callback function, only when all of them are loaded (or errored).
    * @author: H. Yankov (hristo.yankov at gmail dot com)

    It works well,

  15. For anyone who is looking for this, I added keyboard events to the plugin – specifically: right-arrow=next; left-arrow=prev; esc=close.

    Here’s the code I used:
    $(“body”).keydown(function(e){
    if ($(“#fp_close”).is(‘:visible’))
    {
    switch (e.which)
    {
    case 39:
    $(“#fp_next”).click();
    break;
    case 37:
    $(“#fp_prev”).click();
    break;
    case 27:
    $(“#fp_close”).click();
    break;
    }
    }

    });

  16. Hi, great slider! I’ve got a bit of a problem with it though, because I want to add content underneath it but if I scroll down the page and then click one of the images, it doesn’t display the full size picture properly. Here’s a screenshot of what I mean: http://i54.tinypic.com/11vqphg.jpg

    Can someone help please?

  17. Hi, it is possible with the help lightbox in this gallery to open html files?

    Excuse for my bad English πŸ™‚

  18. Beautiful gallery!

    However, sadly, i have the same issue as Robert in Firefox and IE8. Images line wrap when the width gets too wide – letting the last images idsappear into nowwhere πŸ™

  19. How can I hide the whole gallery once it has been opened? There is no remove/destroy function. I want to be able to click on a button and make it disappear and then be able to click on one of the elements in the to show the gallery again.

  20. I’m also with problems running the gallery on IE. The images are not displayed and the button binds seems to be not working… Someone got this? Solutions?

    Anyway, great job! Excelent gallery! (It is working perfectly for me on firefox and chrome)

  21. Great script, I love it!

    For those that are asking on how you can open a gallery when the page loads, you can force a click…

    Add this in your

    $(document).ready(function() {
    $(“#openGallery”).click();
    });

    Then add an ID to your under #fp_galleryList

    Link1
    Link2

    This means when your page loads, there will be a click on #openGallery. This work for me in IE7, IE8, FF3, but doesn’t quite work in Chrome and Safari. Only the first few images load, however when I get to the page a 2nd time all the image are loaded. Not sure what the issue is… maybe somebody else can figure out the rest πŸ™‚

    Thanks,
    D.

  22. I am also having the same issue as Robert and Allan. Its just so random. Other gallerys have the random one picture wrap around while others do not.

  23. I’ve stressed test this plugin and it does not handle well for high res images. I would advice this be used for small projects and images in similar sizes to the original.

  24. The keyboard navigation does not work for me…

    I do not want to have the boxes center aligned, i want to have them on the left side; any ideas?

  25. @Mary Lou

    Thank you for this script! It’s really great.

    I’m having the issue where the last image in a “container” div wraps to the line below and doesn’t appear. This doesn’t happen in the first “container” though – all subsequent containers.

    I believe it’s the same issue Robert, Allanmc, and Johnny Trinh have mentioned.

    I tried many different fixes, but no luck. Doesn’t make sense to me that the 1st set of images works fine, but any after that do not. Also, if I use the first “container,” that works, and repeat it again in the markup, it works fine as well. Any idea how I can fix? Thank you.

    -Bob

  26. Thank you so much for this tutorial, it’s almost exactly what I needed. I only have two questions:

    1 – Is there a way to add a title above the scrollbox based on which gallery is being shown?

    2 – Is there way to add a description area blow the scrollbox based on which gallery is being shown?

  27. I am also having the same issue as Robert, Allanmc, Johnny Trinh and Bob. It starts once there are nine images in a gallery.

    adding after the last image makes the last image show up in the container, but there’s still a little extra at the end of the slider bar that looks bad.

    Any thoughts on how to fix this permanently, without the extra bit on the slider bar?

  28. This gallery looks great. I am just wondering how to have the galley open without clicking the link? I have removed one of the list items- I only need one gallery, I would also like to remove the other link and just have the gallery open…is there a way I could do this?

  29. Hi… M L
    Thx, and great work…
    I need to know, can i on page load force the gallery to show the first city in your example Paris…
    and how…
    Thx again…

  30. If found a way to close the gallery, this is my code:

    function closeGallery()
    {
    $fp_thumbContainer.find(‘.container’).hide();
    $fp_scrollWrapper.fadeOut();
    $fp_thumbContainer.stop()
    .animate({‘height’:’0px’}, 200);
    }

  31. I forget two line, in my function. You need this two other for reopen the gallery:

    gallery_idx = -1;
    $fp_thumbContainer.data(‘opened’, false);

  32. Too bad this doesn’t work with one page layouts. I’m building a page that contains a approx. 6000px wrapper in height and currently facing problems centering the image… I know that is has something to do the the centering function but can’t seem to make it work.

    I’m happy for helping comments :/ …

  33. Awasome as always!
    Please tell me about your code license. May I make modification and use for personal and commercial projects? Thanks before.

    • @Matilda, glad you like it and yes you are free to do that. Please respect the licensing for the images (if you plan to use them). Cheers, ML

  34. ahh, I’m very happy to hear that. Sure I’ll always note your name on the license.txt. I plan to use my own picture.
    Thank you very much, ML.

  35. I really like this tutorial! Want to use it for my portfolio. I am having problems opening the gallery in Safari and IE, but it opens well in Firefox. Any suggestions? Please help!

  36. Unfortunately, i have the same problem as many others, namely that the last image doesn’t show up (it’s invisble on the next line). Only in IE9 for me.. Also, IE9 has a serious problem with the slider. Try it in the demo here on the website; grab the slider control, it won’t work.. Help?

  37. ML, this gallery is beautiful. I wonder if there is a way to implement
    automatic scrolling of images, with an interval between the automatic scrolling…