Happy New Year! We will kick start 2011 with a vibrant image slider tutorial. We will make use of the parallax principle to move different backgrounds when we slide to an image in order to create some nice perspective. This will give a great depth to the whole slider when it’s in […]
Happy New Year! We will kick start 2011 with a vibrant image slider tutorial. We will make use of the parallax principle to move different backgrounds when we slide to an image in order to create some nice perspective. This will give a great depth to the whole slider when it’s in motion.
The HTML structure is going to consist of a main container with the class “pxs_container”. We will add a wrapper for the three different backgrounds which we will animate differently to create the parallax. The background images will have some transparency since we want to see them moving on top of each other.
We will also add a loading element and the two unordered lists for the full images and the thumbnails. Further, we will add the navigation elements.
Now, let’s take a look at the style.
We will start with the main container. Since we will use the whole page for the width of the slider, we will set it to 100%. It will be of position relative because we will set all the element inside to position absolute (and we want them to be positioned relative to the container and not the page):
The wrapper for the divs that will contain the parallax backgrounds will have a repeated background image. This image is just a simple gradient:
The width will be set dynamically in the JavaScript. The single background divs will have all a different background image:
We will also set the left value of these divs dynamically. But we will come back to that later. Let’s take a look at the other elements’ style.
It contains all the elements that we want to load in the beginning, so once loading is done, we will show the wrapper and all its content.
The main idea for the slider list is that we make a really long list with all the li elements having a width of the whole window. So, what you see on screen of the slider is actually one whole li. We will set the width of the ul dynamically to be the window width times the number of images in the list. Making the li elements float left and the correct width of the ul will ensure that the li elements are lined up next to each other:
The slider image inside of the li will be centered horizontally by applying auto margins to the left and right:
Adding a transparent border and a box shadow will create a glass like effect around the image.
The thumbnails list will be positioned absolutely, too. We add a left of 50% because we want to center it, by dynamically setting its width and a negative left margin in the JavaScript:
We’ll add a white border around the thumbnails and give them a slick box shadow:
We will set the left (pxs_prev) and the right (pxs_next) value dynamically in order to stick to the left and right side of the image.
The main idea of this slider is to slide the
images (obviously) and to animate the three backgrounds differently to create
some perspective. So, when we, for example, slide to the next image, we will
animate the left value of the slider ul to minus the window width (because
that’s the width of one li). We will also animate the background div that is
visually the top-most background, but the animation will only be half of the
window width. The background behind that one will move one quarter of the
window width and so on. So the background which is “more far” will move less,
just what the parallax principle describes.
We want to create a plugin out of this script,
so we will initially define some options. We will start by caching the most
important elements.
(function($)
{
$.fn.parallaxSlider = function(options) {
var opts =
$.extend({}, $.fn.parallaxSlider.defaults, options);
return
this.each(function() {
var
$pxs_container = $(this),
o = $.meta ? $.extend({}, opts,
$pxs_container.data()) : opts;
//the main
slider
var
$pxs_slider =
$('.pxs_slider',$pxs_container),
//the
elements in the slider
$elems =
$pxs_slider.children(),
//total
number of elements
total_elems = $elems.length,
//the
navigation buttons
$pxs_next =
$('.pxs_next',$pxs_container),
$pxs_prev =
$('.pxs_prev',$pxs_container),
//the bg
images
$pxs_bg1 =
$('.pxs_bg1',$pxs_container),
$pxs_bg2 =
$('.pxs_bg2',$pxs_container),
$pxs_bg3 =
$('.pxs_bg3',$pxs_container),
//current
image
current = 0,
//the
thumbs container
$pxs_thumbnails = $('.pxs_thumbnails',$pxs_container),
//the
thumbs
$thumbs =
$pxs_thumbnails.children(),
//the
interval for the autoplay mode
slideshow,
//the
loading image
$pxs_loading =
$('.pxs_loading',$pxs_container),
$pxs_slider_wrapper = $('.pxs_slider_wrapper',$pxs_container);
//first,
preload all the images
var
loaded = 0,
$images = $pxs_slider_wrapper.find('img');
$images.each(function(){
var
$img = $(this);
$('<img/>').load(function(){
++loaded;
if(loaded == total_elems*2){
$pxs_loading.hide();
$pxs_slider_wrapper.show();
//width of an image
//(assuming all images have the same sizes)
var one_image_w =
$pxs_slider.find('img:first').width();
/*
set the width of the slider,
of each one of its elements,
and of the
navigation buttons
*/
setWidths($pxs_slider,
$elems,
total_elems,
$pxs_bg1,
$pxs_bg2,
$pxs_bg3,
one_image_w,
$pxs_next,
$pxs_prev);
/*
set the widths of the thumbs
and spread them evenly
*/
$pxs_thumbnails.css({
'width' : one_image_w +
'px',
'margin-left' : -one_image_w/2 + 'px'
});
var spaces =
one_image_w/(total_elems+1);
$thumbs.each(function(i){
var $this = $(this);
var left = spaces*(i+1) -
$this.width()/2;
$this.css('left',left+'px');
if(o.thumbRotation){
var angle = Math.floor(Math.random()*41)-20;
$this.css({
'-moz-transform' : 'rotate('+
angle +'deg)',
'-webkit-transform' : 'rotate('+ angle +'deg)',
'transform' : 'rotate('+ angle +'deg)'
});
}
//hovering the thumbs animates them up and down
$this.bind('mouseenter',function(){
$(this).stop().animate({top:'-10px'},100);
}).bind('mouseleave',function(){
$(this).stop().animate({top:'0px'},100);
});
});
//make the first thumb to be selected
highlight($thumbs.eq(0));
//slide, when clicking the navigation buttons
$pxs_next.bind('click',function(){
++current;
if(current >= total_elems)
if(o.circular)
current = 0;
else{
--current;
return false;
}
highlight($thumbs.eq(current));
slide(current,
$pxs_slider,
$pxs_bg3,
$pxs_bg2,
$pxs_bg1,
o.speed,
o.easing,
o.easingBg);
});
$pxs_prev.bind('click',function(){
--current;
if(current < 0)
if(o.circular)
current =
total_elems - 1;
else{
++current;
return false;
}
highlight($thumbs.eq(current));
slide(current,
$pxs_slider,
$pxs_bg3,
$pxs_bg2,
$pxs_bg1,
o.speed,
o.easing,
o.easingBg);
});
/*
clicking a thumb will slide to the respective image
*/
$thumbs.bind('click',function(){
var $thumb = $(this);
highlight($thumb);
//if autoplay interrupt when user clicks
if(o.auto)
clearInterval(slideshow);
current = $thumb.index();
slide(current,
$pxs_slider,
$pxs_bg3,
$pxs_bg2,
$pxs_bg1,
o.speed,
o.easing,
o.easingBg);
});
/*
activate the autoplay mode if
that option was specified
*/
if(o.auto != 0){
o.circular = true;
slideshow =
setInterval(function(){
$pxs_next.trigger('click');
},o.auto);
}
/*
when resizing the window,
we need to recalculate the widths of the
slider elements, based on the new window width;
we need to slide again to the current one,
since the left of the slider is no longer correct
*/
$(window).resize(function(){
w_w = $(window).width();
setWidths(
$pxs_slider,
$elems,
total_elems,
$pxs_bg1,
$pxs_bg2,
$pxs_bg3,
one_image_w,
$pxs_next,
$pxs_prev
);
slide(
current,
$pxs_slider,
$pxs_bg3,
$pxs_bg2,
$pxs_bg1,
1,
o.easing,
o.easingBg
);
});
}
}).error(function(){
alert('here')
}).attr('src',$img.attr('src'));
});
});
};
//the current
window width
var w_w = $(window).width();
var slide = function(current,
$pxs_slider,
$pxs_bg3,
$pxs_bg2,
$pxs_bg1,
speed,
easing,
easingBg){
var
slide_to = parseInt(-w_w * current);
$pxs_slider.stop().animate({
left : slide_to + 'px'
},speed,
easing);
$pxs_bg3.stop().animate({
left : slide_to/2 + 'px'
},speed,
easingBg);
$pxs_bg2.stop().animate({
left : slide_to/4 + 'px'
},speed,
easingBg);
$pxs_bg1.stop().animate({
left : slide_to/8 + 'px'
},speed,
easingBg);
}
var highlight = function($elem){
$elem.siblings().removeClass('selected');
$elem.addClass('selected');
}
var setWidths = function($pxs_slider,
$elems,
total_elems,
$pxs_bg1,
$pxs_bg2,
$pxs_bg3,
one_image_w,
$pxs_next,
$pxs_prev){
/*
the width of
the slider is the window width
times the
total number of elements in the slider
*/
var
pxs_slider_w = w_w * total_elems;
$pxs_slider.width(pxs_slider_w + 'px');
//each element
will have a width = windows width
$elems.width(w_w + 'px');
/*
we also set
the width of each bg image div.
The value is the same calculated for the
pxs_slider
*/
$pxs_bg1.width(pxs_slider_w + 'px');
$pxs_bg2.width(pxs_slider_w + 'px');
$pxs_bg3.width(pxs_slider_w + 'px');
/*
both, the
right and left of the
navigation
next and previous buttons will be:
windowWidth/2
- imgWidth/2 + some margin
(not to touch
the image borders)
*/
var
position_nav = w_w/2 - one_image_w/2 +
3;
$pxs_next.css('right', position_nav + 'px');
$pxs_prev.css('left', position_nav + 'px');
}
$.fn.parallaxSlider.defaults = {
auto : 0,
speed : 1000,
easing : 'jswing',
easingBg : 'jswing',
circular : true,
thumbRotation : true
};
//easeInOutExpo,easeInBack
})(jQuery);