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.
View demo Download source
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | < 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:
1 2 3 4 5 6 7 | .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:
1 2 3 4 5 6 7 8 9 10 11 12 | .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:
1 2 3 4 5 6 | .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:
1 2 3 4 5 6 7 8 | .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:
1 2 3 | .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):
1 2 3 4 5 6 | .ei-title{
position : absolute ;
right : 50% ;
margin-right : 13% ;
top : 30% ;
}
|
The style for the headings is the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | .ei-title h 2 , .ei-title h 3 {
text-align : right ;
}
.ei-title h 2 {
font-size : 40px ;
line-height : 50px ;
font-family : 'Playfair Display' , serif ;
font-style : italic ;
color : #b5b5b5 ;
}
.ei-title h 3 {
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.
1 2 3 4 5 | .ei-slider-thumbs{
height : 13px ;
margin : 0 auto ;
position : relative ;
}
|
The list elements of the navigation list will be of relative position:
1 2 3 4 5 | .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:
1 2 3 4 5 6 7 8 9 | .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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | .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.2 s 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | .ei-slider-thumbs li img{
position : absolute ;
bottom : 50px ;
opacity : 0 ;
z-index : 999 ;
max-width : 100% ;
transition : all 0.4 s 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:
1 2 3 4 | .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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @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 h 2 , .ei-title h 3 {
text-align : center ;
}
.ei-title h 2 {
font-size : 20px ;
line-height : 24px ;
}
.ei-title h 3 {
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:
1 2 3 4 5 6 7 8 9 | .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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $.Slideshow.defaults = {
animation : 'sides' ,
autoplay : false ,
slideshow_interval : 3000,
speed : 800,
easing : '' ,
titlesFactor : 0.60,
titlespeed : 800,
titleeasing : '' ,
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | _init : function ( options ) {
this .options = $.extend( true , {}, $.Slideshow.defaults, options );
this .$imgItems.css( 'opacity' , 0 );
this .$imgItems.find( 'div.ei-title > *' ).css( 'opacity' , 0 );
this .current = 0;
var _self = this ;
this .$loading = $( '<div class="ei-slider-loading">Loading</div>' ).prependTo( _self.$el );
$.when( this ._preloadImages() ).done( function () {
_self.$loading.hide();
_self._setImagesSize();
_self._initThumbs();
_self.$imgItems.eq( _self.current ).css({
'opacity' : 1,
'z-index' : 10
}).show().find( 'div.ei-title > *' ).css( 'opacity' , 1 );
if ( _self.options.autoplay ) {
_self._startSlideshow();
}
_self._initEvents();
});
},
|
And here are the single functions we just talked about:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | _preloadImages : function () {
var _self = this ,
loaded = 0;
return $.Deferred(
function (dfd) {
_self.$images.each( function ( i ) {
$( '<img>' ).load( function () {
if ( ++loaded === _self.itemsCount ) {
dfd.resolve();
}
}).attr( 'src' , $( this ).attr( 'src' ) );
});
}
).promise();
},
_setImagesSize : function () {
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
this .$sliderElems.css({
'max-width' : this .options.thumbMaxWidth + 'px' ,
'width' : 100 / this .itemsCount + '%'
});
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | _slideTo : function ( pos ) {
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};
if ( this .options.animation === 'sides' ) {
preCSS.left = ( pos > this .current ) ? -1 * this .elWidth : this .elWidth;
animCSS.left = 0;
}
$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(
$currentSlide.css( 'z-index' , 1 ).find( 'div.ei-title > *' ).stop().fadeOut( this .options.speed / 2, function () {
$( this ).show().css( 'opacity' , 0 );
}),
$nextSlide.css( preCSS ).stop().animate( animCSS, this .options.speed, this .options.easing ),
this .$sliderElem.stop().animate({
left : this .$thumbs.eq( pos ).position().left
}, this .options.speed )
).done( function () {
$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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | _initEvents : function () {
var _self = this ;
$(window).on( 'smartresize.eislideshow' , function ( event ) {
_self._setImagesSize();
_self.$sliderElem.css( 'left' , _self.$thumbs.eq( _self.current ).position().left );
});
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;
_self._slideTo( idx );
return false ;
});
}
|
And that’s it! I hope you enjoyed this tutorial and find it useful!
View demo Download source
|