Here is my solution & features it offers:
- Remembers the last position and gradually animate to/from this position
- Block positions are calculated and animated on load and every resize
- Repositioning happens on
$(window).resize()
thus maintaining the fluid nature of the block, despite the use of position absolute
- Support variable heights
- Minor change on existing markup & CSS
On your existing markup, I added a wrapper division.
<div id="wrapper">
<div class="block">
<h2>I'm block 1</h2>
</div>
....
</div>
To maintain the fluidness of the block, I created a function to position the block on the wrapper. Here is the function for position of the blocks:
var reposition = function() {
wrapper = $("#wrapper");
pLeft = 0; //The starting point of all repositioning
pTop = 0;
maxRowHeight = 0;
$(".block").each(function(){
$(this).stop(0,0).animate({
'top' : pTop + 'px',
'left' : pLeft + 'px'
});
pLeft += $(this).width(); //Add the left position for next block
if($(this).height() > maxRowHeight) maxRowHeight = $(this).height(); //Find out the longest block on the row
//If the next block will exceed the width of the wrapper
if(pLeft + $(this).next().width() >= wrapper.innerWidth()) {
pLeft = 0; //reset the left
pTop += maxRowHeight;
maxRowHeight = 0;
}
});
};
Finally, the script to toggle the block
$(".block").click(function() {
$(this).siblings().slideToggle('slow'); //Toggle other blocks
if(!$(this).data('active')){ //if the block is not active
$(this).data('left', $(this).position().left); //sets its left
$(this).data('top', $(this).position().top); // and top position
$(this).animate({ //animate at the top and bottom
top:0,
left:0
},'slow');
$(this).data('active',true);
}else{
$(this).animate({ //animate to its last known position
top:$(this).data('top'),
left:$(this).data('left')
},'slow');
$(this).data('active',false);
}
});
Demos
- Demo[Full] (Resize this to see the fluidness maintained)
- Demo[Full] (version supporting variable heights)