Hey guys. I’ve been writing a few pieces for .NET magazine on CSS3 and thought I’d whip together something lightweight with jQuery to show you how you can use CSS3 transforms to create 3D interactive photo stacks. Below you can see some screenshots of it click here for a demo.


CSS3 has a lot of hidden power in it’s transform function including the ability to do really neat things like skewing an image, rotating it or scaling it, all in just one or two lines of code. You probably know what rotating an image does but how about skewing?
Well, think of skewing as a way to transpose an image at particular angles – basically, pulling the X axis at one angle and the Y axis in another. It sounds a little complicated, but this technique is really great for simulating 3D perspective effects.
In today’s demo, I’ve taken a gallery of images of the jQuery team and transformed them into an interactive 3D stack. CSS3 provides the underlying styling for this whilst jQuery is used for calculations and positioning.
Wanna give it a try? All you need to do is hover over the name of a jQuery team member and they’ll slide out of the stack. You can also run a short ‘snake’ effect on the stack by clicking the respective link in the demo page. The code for everything can be found below.
HTML
CSS3
body {
font-family:Arial;
font-size:13px;
}
.photo,.photoflat {
-moz-transform: scale(1) rotate(0deg) translate(0px, 0px) skew(-21deg, 10deg);
transform-origin: 0% 0%;
-webkit-transform: scale(1) rotate(0deg) translate(0px, 0px) skew(-21deg, 10deg);
-moz-box-shadow:0px 1px 3px #333333 ;
-webkit-box-shadow:0px 1px 3px #333333;
margin-left:-43px;
border:1px solid white;
position:relative;
}
#container { margin:0 auto; margin-top:120px; height:200px; width:900px; -moz-transform: scale(0.7); -webkit-transform: scale(0.7);}
#side2 { margin-left:155px; margin-top:200px;}
.links { margin:0 auto; margin-top:270px; height:100px; width:700px; position:relative;}
.links a { padding:2px; text-decoration:none; color:black;}
.links a:hover {text-decoration:underline;}
.titleviewer {
font-size:40px;
margin-left:621px;
margin-top:-65px;
position:fixed;
z-index:200;
}
h1 { font-family:Arial; font-size:40px; letter-spacing:-1px;}
jQuery
/*Settings*/
var photocount = $('.photo').length;
var factor = 0.3;
var dist = photocount * factor;
var marg1 = -43;
var skew2 = -15;
var imghalf = 36;
var imgw = 0;
var lasthandler = null;
var lastpos = null;
var marginmove = 120;
/*Setup*/
function setupEffect()
{
drawStack();
drawContactLinks();
}
setupEffect();
/*Draw the stack of 3D photos*/
function drawStack()
{
$('.photos .photo').each(function(index) {
dist -= 0.25;
skew2 = skew2 + (index*0.1);
$(this).fadeIn(dist*200);
$(this).css('-moz-transform', 'scale(' + dist + ') skew(' + skew2 +'deg, 0deg)');
$(this).css('-webkit-transform', 'scale(' + dist + ') skew(' + skew2 +'deg, 0deg)');
/*Special transform for the first image*/
if(index==0)
{
$(this).css('-moz-transform', 'scale(' + dist + ') skew(0deg, 0deg)');
$(this).css('-webkit-transform', 'scale(' + dist + ') skew(0deg, 0deg)');
}
/*positioning*/
$(this).css('z-index', index * -1);
marg1 = -45 - index;
$(this).css('margin-left', marg1 + 'px');
});
}
/*Draw the flat photos at the top of the page*/
function drawFlatPhotos()
{
$('.photostop .photoflat').each(function(index) {
dist = 1;
skew2 = (index*0.51);
$(this).fadeIn(dist*200);
$(this).css('-moz-transform','scale(' + dist + ') skew(' + skew2 +'deg, 0deg)');
$(this).css('-webkit-transform', 'scale(' + dist + ') skew(' + skew2 +'deg, 0deg)');
$(this).css('z-index', index * -1);
marg1 = -5 - index;
$(this).css('margin-left', marg1 + 'px');
});
}
drawFlatPhotos();
/*Dynamically draw the links to perform slide-outs*/
function drawContactLinks()
{
$('.photos .photo').each(function(index){
var curphoto = 0;
var handler = null;
var thisphoto = $(this);
var title_attr = thisphoto.attr('title');
var link_html = '' + title_attr + ' ';
var titleviewer = $('.titleviewer');
lasthandler = null;
$('.links').append(link_html);
$('#ph2' + index).hover(function()
{
titleviewer.hide();
titleviewer.html(title_attr);
titleviewer.fadeIn();
handler = $('.photos .photo:eq(' + index +')');
handler.data('originalMargin', handler.css('margin-left'));
lasthandler = handler;
if(index==0)
{
}else{
handler.stop().animate({marginLeft: marginmove + (index*-5)+ 'px'},500);
}
}, function()
{
titleviewer.html('');
if(!(lasthandler==null))
{
lastpos = (lasthandler.data('originalMargin'));
lasthandler.stop().animate({marginLeft: lastpos},500);
}
});
});
}
/*snake effect*/
function autoplaysnake()
{
var handler = null;
var autoplaymargin = 40;
$('.photos .photo').each(function(index){
handler = $('.photos .photo:eq(' + index +')');
handler.data('originalMargin', handler.css('margin-left'));
if(index==0)
{
}else
{
handler.stop().delay(index * 100).animate({marginLeft: autoplaymargin + (index*-5)+ 'px'},500,
function(){
$(this).delay(100).animate({marginLeft:handler.data('originalMargin')},500);
});
}
});
}
$('#auto1').click(function()
{
autoplaysnake();
});
autoplaysnake();
And that’s it!. If you thought this was cool, please feel free to share or retweet the post with your friends and colleagues. Hope this comes in useful somewhere!.
Demo:http://www.addyosmani.com/resources/3dstack
Download Sources:http://www.addyosmani.com/resources/3dstack/3dstack.zip


I just really dig JavaScript. I'm a writer, speaker and a JavaScript developer for AOL (yes, we're still around!).
Great article. It shows well the power of jquery, thanks for sharing !
Very good
Thanks!
Hej Addy,
when you mouse over very fast on each name, the result seems to be different than what you initially planned.
Anyway, nice beginners example
A river dares she!
Nice effect. Loving all these great CSS3/Javascript articles coming out recently
Thanks! I\’m glad to hear you enjoyed them. Lots more to come
how can i use above code in my blog…?
Pingback: Beyond Traditional Image Showcase with jQuery | Hot Scripts Blog
Pingback: 12 Fresh jQuery Image Plugin Tutorials | webdesign14.com
Very! nice
Pingback: Top 100 Useful And Detailed CSS3 Tutorials And Techniques « qeqnes | Designing. jQuery, Ajax, PHP, MySQL and Templates
Pingback: 190+ best! jQuery slider tools – Part III - Pixel2Pixel Design
Pingback: 50 Best jQuery Slider Tools Part 3 | Best Smashing