Elastic Image Slideshow with Thumbnail Preview

Today we want to show you how to create a simple elastic slideshow with a thumbnail preview. The slideshow will adjust automatically to its surrounding container and we can navigate through the slides by using the thumbnail previewer or the autoplay slideshow option.

Today we want to show you how to create a simple elastic slideshow with a thumbnail preview. The slideshow will adjust automatically to its surrounding container and we can navigate through the slides by using the thumbnail previewer or the autoplay slideshow option.

To make this slideshow responsive, we will use a mixture of JavaScript and CSS techniques.

The fabulous photography used in the demo is by Bartek Lurka and it is licensed under the Attribution-NonCommercial-NoDerivs 3.0 Unported License.

So, let’s do it!

The Markup

We will create two unordered lists, one for the main slider and one for the thumbnail navigation beneath the large image. The “large slider” list elements will contain the image and a title with an h2 and h3 element:

<div id="ei-slider" class="ei-slider">
	<ul class="ei-slider-large">
		<li>
			<img src="images/large/1.jpg" alt="image01" />
			<div class="ei-title">
				<h2>Creative</h2>
				<h3>Geek</h3>
			</div>
		</li>
		<li>...</li>
	</ul>
	<ul class="ei-slider-thumbs">
		<li class="ei-slider-element">Current</li>
		<li>
			<a href="#">Slide 1</a>
			<img src="images/thumbs/1.jpg" alt="thumb01" />
		</li>
		<li>...</li>
	</ul>
</div>

The list for the thumbnail preview navigation will contain an absolute element (the first list element with the class ei-slider-element and the thumbnail list elements which consist of an anchor and an image (the thumbnail).

Now, let’s add the style.

The CSS

First, we will define the style for the main wrapper. We will have the slider inside of a wrapper which will be 100% in width in order to stretch over the whole window. Now, the slider itself will also have a width of 100%, making it use all the space there is in width. But we will also define a maximum width, so that the images in our slider don’t get stretched too much when dealing with a big screen:

.ei-slider{
	position: relative;
	width: 100%;
	max-width: 1920px;
	height: 400px;
	margin: 0 auto;
}

While the images are loading, we will add a loading element which will have the following style:

.ei-slider-loading{
	width: 100%;
	height: 100%;
	position: absolute;
	top: 0px;
	left: 0px;
	z-index:999;
	background: rgba(0,0,0,0.9);
	color: #fff;
	text-align: center;
	line-height: 400px;
}

The unordered list will occupy all the space we defined and will not show any overflow:

.ei-slider-large{
	height: 100%;
	width: 100%;
	position:relative;
	overflow: hidden;
}

The list elements that will hold the images will be of absolute position. Depending from where we navigate we will slide them from the left or from the right:

.ei-slider-large li{
	position: absolute;
	top: 0px;
	left: 0px;
	overflow: hidden;
	height: 100%;
	width: 100%;
}

The width of the image will be set in our JavaScript but we also want to define it if we don’t have JS enabled:

.ei-slider-large li img{
	width: 100%;
}

The title holder will be positioned in the middle of the list element with a right margin to fit the picture in our example (and not to overlap the face in the photography):

.ei-title{
	position: absolute;
	right: 50%;
	margin-right: 13%;
	top: 30%;
}

The style for the headings is the following:

.ei-title h2, .ei-title h3{
	text-align: right;
}
.ei-title h2{
	font-size: 40px;
	line-height: 50px;
	font-family: 'Playfair Display', serif;
	font-style: italic;
	color: #b5b5b5;
}
.ei-title h3{
	font-size: 70px;
	line-height: 70px;
	font-family: 'Open Sans Condensed', sans-serif;
	text-transform: uppercase;
	color: #000;
}

The navigation list will have a small height of 13 pixels. We will set a default width for the thumbnails in the initialisation of our plugin. From that width we will set a max-width to the unordered list. This will make it elastic when we resize the window, but not occupy all the width there is.

.ei-slider-thumbs{
	height: 13px;
	margin: 0 auto;
	position: relative;
}

The list elements of the navigation list will be of relative position:

.ei-slider-thumbs li{
	position: relative;
	float: left;
	height: 100%;
}

The special slider element that indicates the current image will be positioned absolutely on top of the current thumbnail element:

.ei-slider-thumbs li.ei-slider-element{
	top: 0px;
	left: 0px;
	position: absolute;
	height: 100%;
	z-index: 10;
	text-indent: -9000px;
	background: rgba(0,0,0,0.9);
}

The link elements will have a white box shadow to show a tiny separation and some darker shadow to appear under them. We’ll also add a transition to the element so that we can change the background-color smoothly on hover:

.ei-slider-thumbs li a{
	display: block;
	text-indent: -9000px;
	background: #666;
	width: 100%;
	height: 100%;
	cursor: pointer;
	box-shadow: 
        0px 1px 1px 0px rgba(0,0,0,0.3), 
        0px 1px 0px 1px rgba(255,255,255,0.5);
    transition: background 0.2s ease;
}
.ei-slider-thumbs li a:hover{
	background-color: #f0f0f0;
}

The image will be positioned absolutely and we will add a transition and a box reflection to it. Adding a max-width to it will make sure that the thumb will adjust to the size of the list element when the window gets smaller than the width of the unordered list itself:

.ei-slider-thumbs li img{
	position: absolute;
	bottom: 50px;
	opacity: 0;
	z-index: 999;
	max-width: 100%;
    transition: all 0.4s ease;
	-webkit-box-reflect: 
        below 0px -webkit-gradient(
            linear, 
            left top, 
            left bottom, 
            from(transparent), 
            color-stop(50%, transparent), 
            to(rgba(255,255,255,0.3))
            );
}

On hover, we will animate the opacity and the bottom value so that it appears to be sliding in from the top:

.ei-slider-thumbs li:hover img{
	opacity: 1;
	bottom: 13px;
}

Last but not least, we want to make sure that from a certain width on, the slider title will not cover the best parts of our image. So, we will make it appear at the bottom of the image with a semi-transparent white background:

@media screen and (max-width: 830px) {
	.ei-title{
		position: absolute;
		right: 0px;
		margin-right: 0px;
		width: 100%;
		text-align: center;
		top: auto;
		bottom: 10px;
		background: rgba(255,255,255,0.9);
		padding: 5px 0;
	}
	.ei-title h2, .ei-title h3{
		text-align: center;
	}
	.ei-title h2{
		font-size: 20px;
		line-height: 24px;
	}
	.ei-title h3{
		font-size: 30px;
		line-height: 40px;
	}
}

For the case that we don’t have JavaScript enabled we will add this piece of CSS to ensure that our slides are shown. We will hide the thumbnail navigation:

.ei-slider{
	height: auto;
}
.ei-slider-thumbs{
	display: none;
}
.ei-slider-large li{
	position: relative;
}

And that’s all the style! Let’s take a look at the JavaScript.

The JavaScript

Since we are creating a plugin, let’s first look at the definition of the options:

$.Slideshow.defaults 		= {
	// animation types:
	// "sides" : new slides will slide in from left / right
	// "center": new slides will appear in the center
	animation			: 'sides', // sides || center
	// if true the slider will automatically 
	// slide, and it will only stop if the user 
	// clicks on a thumb
	autoplay			: false,
	// interval for the slideshow
	slideshow_interval	: 3000,
	// speed for the sliding animation
	speed			: 800,
	// easing for the sliding animation
	easing			: '',
	// percentage of speed for the titles animation. 
	// Speed will be speed * titlesFactor
	titlesFactor		: 0.60,
	// titles animation speed
	titlespeed			: 800,
	// titles animation easing
	titleeasing			: '',
	// maximum width for the thumbs in pixels
	thumbMaxWidth		: 150
};

In the _init funtion we will start by setting the opacity of the title elements and the images to 0. We will also preload the images and once they are loaded we will set their size and position according to the slider width and height. Then we configure the thumbnails navigation by setting the width of the unordered list and the list items.

We will then show the first slide and if we set autoplay in our options to true, then we’ll start the slideshow. The we initialize the events which are the events for resizing the window and for clicking the thumbnails:

_init 				: function( options ) {
			
	this.options 		= $.extend( true, {}, $.Slideshow.defaults, options );
	
	// set the opacity of the title elements and the image items
	this.$imgItems.css( 'opacity', 0 );
	this.$imgItems.find('div.ei-title > *').css( 'opacity', 0 );
	
	// index of current visible slider
	this.current		= 0;
	
	var _self			= this;
	
	// preload images
	// add loading status
	this.$loading		= $('
Loading
').prependTo( _self.$el ); $.when( this._preloadImages() ).done( function() { // hide loading status _self.$loading.hide(); // calculate size and position for each image _self._setImagesSize(); // configure thumbs container _self._initThumbs(); // show first _self.$imgItems.eq( _self.current ).css({ 'opacity' : 1, 'z-index' : 10 }).show().find('div.ei-title > *').css( 'opacity', 1 ); // if autoplay is true if( _self.options.autoplay ) { _self._startSlideshow(); } // initialize the events _self._initEvents(); }); },

And here are the single functions we just talked about:

_preloadImages		: function() {
	
	// preloads all the large images
	
	var _self	= this,
		loaded	= 0;
	
	return $.Deferred(
	
		function(dfd) {
	
			_self.$images.each( function( i ) {
				
				$('').load( function() {
				
					if( ++loaded === _self.itemsCount ) {
					
						dfd.resolve();
						
					}
				
				}).attr( 'src', $(this).attr('src') );
			
			});
			
		}
		
	).promise();
	
},
_setImagesSize		: function() {
	
	// save ei-slider's width
	this.elWidth	= this.$el.width();
	
	var _self	= this;
	
	this.$images.each( function( i ) {
		
		var $img	= $(this);
			imgDim	= _self._getImageDim( $img.attr('src') );
			
		$img.css({
			width		: imgDim.width,
			height		: imgDim.height,
			marginLeft	: imgDim.left,
			marginTop	: imgDim.top
		});
		
	});

},
_getImageDim		: function( src ) {
	
	var $img    = new Image();
					
	$img.src    = src;
			
	var c_w		= this.elWidth,
		c_h		= this.$el.height(),
		r_w		= c_h / c_w,
		
		i_w		= $img.width,
		i_h		= $img.height,
		r_i		= i_h / i_w,
		new_w, new_h, new_left, new_top;
			
	if( r_w > r_i ) {
		
		new_h	= c_h;
		new_w	= c_h / r_i;
	
	}
	else {
	
		new_h	= c_w * r_i;
		new_w	= c_w;
	
	}
			
	return {
		width	: new_w,
		height	: new_h,
		left	: ( c_w - new_w ) / 2,
		top		: ( c_h - new_h ) / 2
	};

},
_initThumbs			: function() {

	// set the max-width of the slider elements to the one set in the plugin's options
	// also, the width of each slider element will be 100% / total number of elements
	this.$sliderElems.css({
		'max-width' : this.options.thumbMaxWidth + 'px',
		'width'		: 100 / this.itemsCount + '%'
	});
	
	// set the max-width of the slider and show it
	this.$sliderthumbs.css( 'max-width', this.options.thumbMaxWidth * this.itemsCount + 'px' ).show();
	
},
_startSlideshow		: function() {

	var _self	= this;
	
	this.slideshow	= setTimeout( function() {
		
		var pos;
		
		( _self.current === _self.itemsCount - 1 ) ? pos = 0 : pos = _self.current + 1;
		
		_self._slideTo( pos );
		
		if( _self.options.autoplay ) {
		
			_self._startSlideshow();
		
		}
	
	}, this.options.slideshow_interval);

},

The _slideTo function will take care of the transition between the slides. Depending on what we’ve set in our options, we’ll either make the new slide appear from the side or simply make it fade in without sliding it. We’ll also take care of the title and its heading elements which we will slightly slide from the sides by setting their right margins. The thumbnail slider element will have to move to the new corresponding thumbnail position.

_slideTo			: function( pos ) {
	
	// return if clicking the same element or if currently animating
	if( pos === this.current || this.isAnimating )
		return false;
	
	this.isAnimating	= true;
	
	var $currentSlide	= this.$imgItems.eq( this.current ),
		$nextSlide		= this.$imgItems.eq( pos ),
		_self			= this,
		
		preCSS			= {zIndex	: 10},
		animCSS			= {opacity	: 1};
	
	// new slide will slide in from left or right side
	if( this.options.animation === 'sides' ) {
		
		preCSS.left		= ( pos > this.current ) ? -1 * this.elWidth : this.elWidth;
		animCSS.left	= 0;
	
	}	
	
	// titles animation
	$nextSlide.find('div.ei-title > h2')
			  .css( 'margin-right', 50 + 'px' )
			  .stop()
			  .delay( this.options.speed * this.options.titlesFactor )
			  .animate({ marginRight : 0 + 'px', opacity : 1 }, this.options.titlespeed, this.options.titleeasing )
			  .end()
			  .find('div.ei-title > h3')
			  .css( 'margin-right', -50 + 'px' )
			  .stop()
			  .delay( this.options.speed * this.options.titlesFactor )
			  .animate({ marginRight : 0 + 'px', opacity : 1 }, this.options.titlespeed, this.options.titleeasing )
	
	$.when(
		
		// fade out current titles
		$currentSlide.css( 'z-index' , 1 ).find('div.ei-title > *').stop().fadeOut( this.options.speed / 2, function() {
			// reset style
			$(this).show().css( 'opacity', 0 );	
		}),
		
		// animate next slide in
		$nextSlide.css( preCSS ).stop().animate( animCSS, this.options.speed, this.options.easing ),
		
		// "sliding div" moves to new position
		this.$sliderElem.stop().animate({
			left	: this.$thumbs.eq( pos ).position().left
		}, this.options.speed )
		
	).done( function() {
		
		// reset values
			$currentSlide.css( 'opacity' , 0 ).find('div.ei-title > *').css( 'opacity', 0 );
			$nextSlide.css( 'z-index', 1 );
			_self.current	= pos;
			_self.isAnimating		= false;
		
		});
		
},

The _initEvents function will recalculate the sizes of the images when we resize the window and reposition the thumbnail slider element. When clicking on a thumbnail we will show the regarding slide:

_initEvents			: function() {
	
	var _self	= this;
	
	// window resize
	$(window).on( 'smartresize.eislideshow', function( event ) {
		
		// resize the images
		_self._setImagesSize();
	
		// reset position of thumbs sliding div
		_self.$sliderElem.css( 'left', _self.$thumbs.eq( _self.current ).position().left );
	
	});
	
	// click the thumbs
	this.$thumbs.on( 'click.eislideshow', function( event ) {
		
		if( _self.options.autoplay ) {
		
			clearTimeout( _self.slideshow );
			_self.options.autoplay	= false;
		
		}
		
		var $thumb	= $(this),
			idx		= $thumb.index() - 1; // exclude sliding div
			
		_self._slideTo( idx );
		
		return false;
	
	});
	
}

And that’s it! I hope you enjoyed this tutorial and find it 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 98

Comments are closed.
  1. Awesome mary lou! but it wouldn’t be great to have stop and play buttons? or maybe one to advance..?
    Just saying ? take care!!

  2. ajeiajeiajei mary lou!!! what you eat, why you can clever like that?
    hmmm…

    Like me pict on the demo ๐Ÿ˜€

  3. Good tutorial. I can definitely see myself using this in one of my future web projects. It creates some extra interactivity to a normal slideshow and makes the website more interesting for the user. The small preview of the next slide is also a nice touch.

  4. It’s always a pleasure to view your work.

    It even degrades pretty nicely in IE6. There is a small flaw with the the duplication of the first thumbnail…but easily overlooked by a user.

  5. This is completely amazing and exactly what I was looking for the past 3 days. Can’t wait to use it on a new project.

    Thank you very much for this incredible tutorial.

  6. Hi Mary.

    Thanks for such a wonderful tutorial. I am using this on my new project. And it is looking great. My problem is that i am not a JS guy at all. So trying to make this work for a different number of images is not turning out as expected. Does the plugin understand and automatically calculate the various widths ? How to go about making it work with a fewer images and of a different size from the tutorial? Thanks for your time on this.

  7. anyone who has a good jQuery image viewer with a audio player integrated? i’m code illiterate…

  8. Hi fellows, I wish to share my interest of emulate the effect with transitions, side by side of the screen with 3 different slide boxes. Just like: patinagroup.com

    Anybody can advise if there is a script to achieve it?

    I did a begginer trial with my site: caiotres.com.mx
    Suggestions?

  9. $.Deferred is not a function – Error

    _preloadImages : function() {

    // preloads all the large images

    var _self = this,
    loaded = 0;

    return $.Deferred(

    function(dfd) {

    _self.$images.each( function( i ) {

    $(”).load( function() {

    if( ++loaded === _self.itemsCount ) {

    dfd.resolve();

    }

    }).attr( ‘src’, $(this).attr(‘src’) );

    });

    }

    ).promise();

    },

  10. the thumbnail not working properly on IE7, all the thumbnail showing up in a line. Appreciate if you can help…

  11. Hey!

    Thanks for sharing and i wanna to use this slideshow in one of my project… MAY I …..???

  12. hi marry,….. this is simply superb… stylish and international look……… thanks….. im going to use this for my next project….

  13. IE7 thumbnail problem!

    in style.css

    find this line : -ms-filter: “progid:DXImageTransform.Microsoft.Alpha(Opacity=0)”;

    and add below line :
    filter: alpha(opacity=0);

    find this line : -ms-filter: “progid:DXImageTransform.Microsoft.Alpha(Opacity=100)”;

    and add below line:
    filter: alpha(opacity=100);

    thats it.
    have a nice day.
    thank you mary

  14. Im getting an error:

    Uncaught TypeError: Object [object Object] has no method

    Any ideas?

  15. Hello great job with this slider.

    I need some help, i did make it work until i tried in IE, it become enormous displaying all the images in it full sizes can any one help me please?

    tks

  16. Hey this is a great piece of work, I need help in using this javascript for a single image. So when window resizes to small width (eg. 800px) image needs to stay in center no change in width and height ?

    Can you help me out ?

  17. I can’t get the thumb animation by mouseover in IE7 and IE8. Anyone who get this done?

  18. Great technique Mary Lou!
    I’m using it with jQuery localScroll but I have a problem….
    is there a way I can trigger the animation through function call and NOT with the CLICK event ?
    Thank you in advance ๐Ÿ˜‰

  19. Nice work, but I wish the tutorial was a little more in-depth, there seems to be missing information, I couldn’t get it to work following the tutorial until I looked at the code and realized that you need to include the jQuery easing file and still I had problems getting to work ???

  20. is there a way this could work full screen with the thumbnails running along the booom of the page and having a fluid width also?

    • Any luck there? trying to find the answer to the same question…

      I’ve managed to make it full screen but I’m struggling to get the thumbnail bar to take the full width at the bottom… Did you get it to work?

      thanks a lot for your help.

      Y

  21. is there a way this could work full screen with the thumbnails running along the bottom of the page and having a fluid width also? please a reply would be greatly appreciated

    • I’m currently working on the modifications to do so with comments added on why my changes happened. I’ll notify you if I am successful.

    • Altering the bottom property of the classes (.ei-slider-thumbs li img) and (.ei-slider-thumbs li:hover img) to negative whatever the height or your thumb images will drop the thumnail strip down below the viewer. I have’t dug into the js files to find any applicable code there yet, but this is a simple solution

    • Any of you guys found the solution? I’m trying to have the thumbnails to take 100% of the width and be right at the bottom, over the slider. If I add a it jumps to the next line instead of taking all the width of the browser. Not sure what causes it…

      If you have an answer I’d really appreciate, thanks a lot!

      Y

  22. I’m having problem’s with the way the thumb nails are viewing in firefox. When they pop up on a hover over they appear to the right of the button? any ideas why they look fine in safari!

    Kind regards

    Chris

  23. Yes Chris, I had the same problem with the FF after change the code, but the original remain working fine.
    It only stopped adjusting along to the window in IE8. And even with the original source code downloaded it isn’t resizing any more. Does someone facing the same problem?

    by the way, I liked anyways! thnx ๐Ÿ˜‰

  24. I’m back with the FF’s fix. But I’m still having the same problem on IE8.
    In the style.css I changed the following:
    .ei-slider-thumbs li img{ position: relative; /*before = absolute;*/ bottom: 85px; /*before = 50px;*/ ...
    also this:
    .ei-slider-thumbs li:hover img{ ... bottom: 60px; /*before = 13px;*/ ...
    It worked to me. Hope this helps…
    p.s.: In order to the position remain the same by resizing the window, I think it will need a javascript for both the original and changed code.

  25. I really love this slider. but Im a noob for web scripting. how can I add this into my wordpress? maybe someone can tell me how to make this slider into a wordpress plugin?

    thanks- I would be verry happy to hear the answer ๐Ÿ˜€

  26. How can i modify the autoplay to loop the slideshow? (at the moment at the last image it stops?)