Splitting and dividing images on a jQuery slideshow is not so difficult as it could seem at a first glance. In fact, if you know the technique that works behind the scenes, you'll probably end up with realizing how this feature is simple in its implementation. In a nutshell: it's only a matter of layers and background images. Let's see the details.
The markup
We have a very simple and common slideshow structure:
<div id="slideshow">
<div id="slideshow-wrapper">
<div class="slide">
<img src="img/1.jpg" alt="" />
</div>
<div class="slide">
<img src="img/2.jpg" alt="" />
</div>
<div class="slide">
<img src="img/3.jpg" alt="" />
</div>
<div class="slide">
<img src="img/4.jpg" alt="" />
</div>
</div>
</div>
Each image is 1150 x 400 pixels wide. We have to create a grid made up of 40 blocks and 4 rows to be applied on each slide. Each row is made up of 10 blocks. In turn, each block is 115 x 100 pixels wide, so (115 x 10) and (100 x 4) give us the total image dimensions. Here comes the trick: each of these blocks will have the current image as its background image, but with different x and y values for the CSS background-position property. Once set the blocks, it's easy to animate them with jQuery.
The CSS styles
Our CSS styles are as follows:
#slideshow {
margin: 2em auto;
width: 90%;
max-width: 1150px;
height: 400px;
border: 5px solid #565656;
overflow: hidden;
position: relative;
}
#slideshow-wrapper {
width: 4600px;
height: 400px;
position: relative;
background: #ccc;
}
#slideshow-wrapper img {
width: 1150px;
height: 400px;
display: none;
}
div.slide {
float: left;
width: 1150px;
height: 400px;
position: relative;
}
div.overlay {
width: 1150px;
height: 400px;
position: absolute;
top: 0;
left: 0;
}
div.row {
height: 100px;
position: relative;
}
div.piece {
height: 100px;
width: 115px;
background-repeat: no-repeat;
float: left;
display: none;
}
The jQuery code
We start with a singleton object and we declare the properties and variables used throughout its namespace:
var Slideshow = new function() {
var slideshow = document.getElementById('slideshow'),
wrapper = $('#slideshow-wrapper', slideshow),
slides = $('div.slide', wrapper),
pieces = $('div.piece', slides),
index = -1,
timer = null;
// continues
}();
Then we split each slide into pieces using the following private method:
var Slideshow = new function() {
var slideshow = document.getElementById('slideshow'),
wrapper = $('#slideshow-wrapper', slideshow),
slides = $('div.slide', wrapper),
pieces = $('div.piece', slides),
index = -1,
timer = null;
var insertBlocks = function() {
slides.each(function() {
var slide = $(this);
$('<div class="overlay"/>').appendTo(slide);
var block = '<div class="row">' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'</div>';
for(var i = 0; i < 4; i += 1) {
$(block).appendTo($('div.overlay', slide));
}
});
};
// continues
}();
Then we set the background images:
var Slideshow = new function() {
var slideshow = document.getElementById('slideshow'),
wrapper = $('#slideshow-wrapper', slideshow),
slides = $('div.slide', wrapper),
pieces = $('div.piece', slides),
index = -1,
timer = null;
var insertBlocks = function() {
slides.each(function() {
var slide = $(this);
$('<div class="overlay"/>').appendTo(slide);
var block = '<div class="row">' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'</div>';
for(var i = 0; i < 4; i += 1) {
$(block).appendTo($('div.overlay', slide));
}
});
};
var setBackgroundImages = function() {
slides.each(function() {
var slide = $(this);
var src = $('img', slide).attr('src');
var pieces = $('div.piece', slide);
pieces.css('backgroundImage', 'url(' + src + ')');
pieces.eq(0).css('backgroundPosition', '0px 0px');
pieces.eq(1).css('backgroundPosition', '-115px 0px');
pieces.eq(2).css('backgroundPosition', '-230px 0px');
pieces.eq(3).css('backgroundPosition', '-345px 0px');
pieces.eq(4).css('backgroundPosition', '-460px 0px');
pieces.eq(5).css('backgroundPosition', '-575px 0px');
pieces.eq(6).css('backgroundPosition', '-690px 0px');
pieces.eq(7).css('backgroundPosition', '-805px 0px');
pieces.eq(8).css('backgroundPosition', '-925px 0px');
pieces.eq(9).css('backgroundPosition', '-1040px 0px');
pieces.eq(10).css('backgroundPosition', '0px -100px');
pieces.eq(11).css('backgroundPosition', '-115px -100px');
pieces.eq(12).css('backgroundPosition', '-230px -100px');
pieces.eq(13).css('backgroundPosition', '-345px -100px');
pieces.eq(14).css('backgroundPosition', '-460px -100px');
pieces.eq(15).css('backgroundPosition', '-575px -100px');
pieces.eq(16).css('backgroundPosition', '-690px -100px');
pieces.eq(17).css('backgroundPosition', '-805px -100px');
pieces.eq(18).css('backgroundPosition', '-925px -100px');
pieces.eq(19).css('backgroundPosition', '-1040px -100px');
pieces.eq(20).css('backgroundPosition', '0px -200px');
pieces.eq(21).css('backgroundPosition', '-115px -200px');
pieces.eq(22).css('backgroundPosition', '-230px -200px');
pieces.eq(23).css('backgroundPosition', '-345px -200px');
pieces.eq(24).css('backgroundPosition', '-460px -200px');
pieces.eq(25).css('backgroundPosition', '-575px -200px');
pieces.eq(26).css('backgroundPosition', '-690px -200px');
pieces.eq(27).css('backgroundPosition', '-805px -200px');
pieces.eq(28).css('backgroundPosition', '-925px -200px');
pieces.eq(29).css('backgroundPosition', '-1040px -200px');
pieces.eq(30).css('backgroundPosition', '0px -300px');
pieces.eq(31).css('backgroundPosition', '-115px -300px');
pieces.eq(32).css('backgroundPosition', '-230px -300px');
pieces.eq(33).css('backgroundPosition', '-345px -300px');
pieces.eq(34).css('backgroundPosition', '-460px -300px');
pieces.eq(35).css('backgroundPosition', '-575px -300px');
pieces.eq(36).css('backgroundPosition', '-690px -300px');
pieces.eq(37).css('backgroundPosition', '-805px -300px');
pieces.eq(38).css('backgroundPosition', '-925px -300px');
pieces.eq(39).css('backgroundPosition', '-1040px -300px');
});
};
// continues
}();
It's verbose but doing so is the best way to help you understand how it works. Now we have to animate the slideshow:
var Slideshow = new function() {
var slideshow = document.getElementById('slideshow'),
wrapper = $('#slideshow-wrapper', slideshow),
slides = $('div.slide', wrapper),
pieces = $('div.piece', slides),
index = -1,
timer = null;
var insertBlocks = function() {
slides.each(function() {
var slide = $(this);
$('<div class="overlay"/>').appendTo(slide);
var block = '<div class="row">' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'</div>';
for(var i = 0; i < 4; i += 1) {
$(block).appendTo($('div.overlay', slide));
}
});
};
var setBackgroundImages = function() {
slides.each(function() {
var slide = $(this);
var src = $('img', slide).attr('src');
var pieces = $('div.piece', slide);
pieces.css('backgroundImage', 'url(' + src + ')');
pieces.eq(0).css('backgroundPosition', '0px 0px');
pieces.eq(1).css('backgroundPosition', '-115px 0px');
pieces.eq(2).css('backgroundPosition', '-230px 0px');
pieces.eq(3).css('backgroundPosition', '-345px 0px');
pieces.eq(4).css('backgroundPosition', '-460px 0px');
pieces.eq(5).css('backgroundPosition', '-575px 0px');
pieces.eq(6).css('backgroundPosition', '-690px 0px');
pieces.eq(7).css('backgroundPosition', '-805px 0px');
pieces.eq(8).css('backgroundPosition', '-925px 0px');
pieces.eq(9).css('backgroundPosition', '-1040px 0px');
pieces.eq(10).css('backgroundPosition', '0px -100px');
pieces.eq(11).css('backgroundPosition', '-115px -100px');
pieces.eq(12).css('backgroundPosition', '-230px -100px');
pieces.eq(13).css('backgroundPosition', '-345px -100px');
pieces.eq(14).css('backgroundPosition', '-460px -100px');
pieces.eq(15).css('backgroundPosition', '-575px -100px');
pieces.eq(16).css('backgroundPosition', '-690px -100px');
pieces.eq(17).css('backgroundPosition', '-805px -100px');
pieces.eq(18).css('backgroundPosition', '-925px -100px');
pieces.eq(19).css('backgroundPosition', '-1040px -100px');
pieces.eq(20).css('backgroundPosition', '0px -200px');
pieces.eq(21).css('backgroundPosition', '-115px -200px');
pieces.eq(22).css('backgroundPosition', '-230px -200px');
pieces.eq(23).css('backgroundPosition', '-345px -200px');
pieces.eq(24).css('backgroundPosition', '-460px -200px');
pieces.eq(25).css('backgroundPosition', '-575px -200px');
pieces.eq(26).css('backgroundPosition', '-690px -200px');
pieces.eq(27).css('backgroundPosition', '-805px -200px');
pieces.eq(28).css('backgroundPosition', '-925px -200px');
pieces.eq(29).css('backgroundPosition', '-1040px -200px');
pieces.eq(30).css('backgroundPosition', '0px -300px');
pieces.eq(31).css('backgroundPosition', '-115px -300px');
pieces.eq(32).css('backgroundPosition', '-230px -300px');
pieces.eq(33).css('backgroundPosition', '-345px -300px');
pieces.eq(34).css('backgroundPosition', '-460px -300px');
pieces.eq(35).css('backgroundPosition', '-575px -300px');
pieces.eq(36).css('backgroundPosition', '-690px -300px');
pieces.eq(37).css('backgroundPosition', '-805px -300px');
pieces.eq(38).css('backgroundPosition', '-925px -300px');
pieces.eq(39).css('backgroundPosition', '-1040px -300px');
});
};
var autoSlide = function() {
timer = setInterval(function() {
index++;
if(index == (slides.length - 1)) {
index = -1;
}
wrapper.animate({
left: - slides.eq(index).position().left
}, 0, function() {
var slide = slides.eq(index);
var parts = $('div.piece', slide);
var counter = -1;
var slicer = null;
slicer = setInterval(function() {
counter++;
if(counter == (parts.length)) {
clearInterval(slicer);
parts.fadeOut();
}
parts.eq(counter).fadeIn(75);
}, 75);
});
}, 3000);
};
// continues
}();
Finally, we create an initialization public method:
var Slideshow = new function() {
var slideshow = document.getElementById('slideshow'),
wrapper = $('#slideshow-wrapper', slideshow),
slides = $('div.slide', wrapper),
pieces = $('div.piece', slides),
index = -1,
timer = null;
var insertBlocks = function() {
slides.each(function() {
var slide = $(this);
$('<div class="overlay"/>').appendTo(slide);
var block = '<div class="row">' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'<div class="piece"></div>' +
'</div>';
for(var i = 0; i < 4; i += 1) {
$(block).appendTo($('div.overlay', slide));
}
});
};
var setBackgroundImages = function() {
slides.each(function() {
var slide = $(this);
var src = $('img', slide).attr('src');
var pieces = $('div.piece', slide);
pieces.css('backgroundImage', 'url(' + src + ')');
pieces.eq(0).css('backgroundPosition', '0px 0px');
pieces.eq(1).css('backgroundPosition', '-115px 0px');
pieces.eq(2).css('backgroundPosition', '-230px 0px');
pieces.eq(3).css('backgroundPosition', '-345px 0px');
pieces.eq(4).css('backgroundPosition', '-460px 0px');
pieces.eq(5).css('backgroundPosition', '-575px 0px');
pieces.eq(6).css('backgroundPosition', '-690px 0px');
pieces.eq(7).css('backgroundPosition', '-805px 0px');
pieces.eq(8).css('backgroundPosition', '-925px 0px');
pieces.eq(9).css('backgroundPosition', '-1040px 0px');
pieces.eq(10).css('backgroundPosition', '0px -100px');
pieces.eq(11).css('backgroundPosition', '-115px -100px');
pieces.eq(12).css('backgroundPosition', '-230px -100px');
pieces.eq(13).css('backgroundPosition', '-345px -100px');
pieces.eq(14).css('backgroundPosition', '-460px -100px');
pieces.eq(15).css('backgroundPosition', '-575px -100px');
pieces.eq(16).css('backgroundPosition', '-690px -100px');
pieces.eq(17).css('backgroundPosition', '-805px -100px');
pieces.eq(18).css('backgroundPosition', '-925px -100px');
pieces.eq(19).css('backgroundPosition', '-1040px -100px');
pieces.eq(20).css('backgroundPosition', '0px -200px');
pieces.eq(21).css('backgroundPosition', '-115px -200px');
pieces.eq(22).css('backgroundPosition', '-230px -200px');
pieces.eq(23).css('backgroundPosition', '-345px -200px');
pieces.eq(24).css('backgroundPosition', '-460px -200px');
pieces.eq(25).css('backgroundPosition', '-575px -200px');
pieces.eq(26).css('backgroundPosition', '-690px -200px');
pieces.eq(27).css('backgroundPosition', '-805px -200px');
pieces.eq(28).css('backgroundPosition', '-925px -200px');
pieces.eq(29).css('backgroundPosition', '-1040px -200px');
pieces.eq(30).css('backgroundPosition', '0px -300px');
pieces.eq(31).css('backgroundPosition', '-115px -300px');
pieces.eq(32).css('backgroundPosition', '-230px -300px');
pieces.eq(33).css('backgroundPosition', '-345px -300px');
pieces.eq(34).css('backgroundPosition', '-460px -300px');
pieces.eq(35).css('backgroundPosition', '-575px -300px');
pieces.eq(36).css('backgroundPosition', '-690px -300px');
pieces.eq(37).css('backgroundPosition', '-805px -300px');
pieces.eq(38).css('backgroundPosition', '-925px -300px');
pieces.eq(39).css('backgroundPosition', '-1040px -300px');
});
};
var autoSlide = function() {
timer = setInterval(function() {
index++;
if(index == (slides.length - 1)) {
index = -1;
}
wrapper.animate({
left: - slides.eq(index).position().left
}, 0, function() {
var slide = slides.eq(index);
var parts = $('div.piece', slide);
var counter = -1;
var slicer = null;
slicer = setInterval(function() {
counter++;
if(counter == (parts.length)) {
clearInterval(slicer);
parts.fadeOut();
}
parts.eq(counter).fadeIn(75);
}, 75);
});
}, 3000);
};
this.init = function() {
insertBlocks();
setBackgroundImages();
autoSlide();
};
}();
And we kick things off:
$(function() {
Slideshow.init();
});
You can see the demo below.
so cool...so split :D
Great Stuff!