Moving Boxes Content with jQuery

Today we will create a website template with some really sweet animations using jQuery. The idea is to have little boxes scattered around at the top of the site and […]

Today we will create a website template with some really sweet animations using jQuery. The idea is to have little boxes scattered around at the top of the site and when a menu item is clicked, the boxes animate to form the main content area. We will use some different animation effects that we will add as options to the menu item.

The content area will custom scroll for which we will be using the really awesome jScrollPane Plugin by Kevin Luck. We will also use the jQuery 2d transformation plugin by Grady in order to rotate the little boxes while we animate them, and the the jQuery Easing Plugin for some spice.

The beautiful photos are by Jin. Visit his Flickr photostream at http://www.flickr.com/photos/jinthai/

So, let’s start!

The Markup

First, we want to place the background image with the grid overlay:

<div id="mb_background" class="mb_background">
	<img class="mb_bgimage" src="images/default.jpg" alt="Background"/>
	<div class="mb_overlay"></div>
</div>

The next div element will be used to add the little boxes with their random position and rotation degree

<div id="mb_pattern" class="mb_pattern"></div>

We will place a total of 16 boxes (div elements) into this container.
The menu and the heading will have the following HTML stucture:

<div class="mb_heading">
	<h1>Lack of Color</h1>
</div>

<div id="mb_menu" class="mb_menu">
	<a href="#" data-speed="600" data-easing="easeOutBack">About</a>
	<a href="#" data-speed="1000" data-easing="easeInExpo">Work</a>
	<a href="#" data-speed="600" data-easing="easeOutBack">Media</a>
	<a href="#" data-speed="1000" data-easing="easeInExpo">Contact</a>
</div>

As you can see, we will add two “data-” attributes that we’ll use to define the speed and the easing effect that will be associated to the animation of the boxes. Read more about these new custom data attributes of HTML5 on John Resig’s blog: HTML 5 data- Attributes
Next, we will define the structure for the content area. There will be a main wrapper with the class “mb_content_wrapper” which contains all the content containers that have the class “mb_content” and a span for the closing cross:

<div id="mb_content_wrapper" class="mb_content_wrapper">
	<span class="mb_close"></span>
	<div class="mb_content">
		<h2>About</h2>
		<div class="mb_content_inner">
			<p>Some text...</p>
		</div>
	</div>
	<div class="mb_content">
		...
	</div>
	<div class="mb_content">
		...
	</div>
	<div class="mb_content">
		...
	</div>
</div>

One of the content elements is going to contain a list of images:

<div class="mb_content_inner">
	<p>...</p>
	<ul id="mb_imagelist" class="mb_imagelist">
		<li><img src="images/small/1.jpg" alt="image1" data-bgimg="images/image1.jpg"/></li>
		<li><img src="images/small/2.jpg" alt="image2" data-bgimg="images/image2.jpg"/></li>
		<li>...</li>
	</ul>
	<p>...</p>
</div>

And that’s all the HTML. Now, let’s make it pretty!

The CSS

First, we will embed our reset.css that will reset all the basic styles, and we’ll define some main properties:

@import url('reset.css');

body{
	background:#000;
	color:#fff;
	font-family: 'PT Sans Narrow', Arial, sans-serif;
}
a{
	color:#fff;
	text-decoration:none;
}

Next, we will define the styles for the image that we will use as a background and the overlay pattern:

img.mb_bgimage{
	position:fixed;
	left:0px;
	top:0px;
	width:100%;
	opacity:0.8;
	z-index:1;
}
.mb_overlay{
	width:100%;
	height:100%;
	position:fixed;
	top:0px;
	left:0px;
	background:transparent url(../images/pattern.png) repeat top left;
	z-index:2;
}

They will both be of fixed positioning and we will give them a low z-index so that they really stay under everything else.

The little boxes will all have a height and width of 50 pixel and they will have absolute positioning:

.mb_pattern div{
	position:absolute;
	width:50px;
	height:50px;
	background:#000;
	z-index:10;
}

The main heading will also be positioned absolutely and we will use a font-face from the collection of Google Web Fonts:

.mb_heading h1{
	position:absolute;
	top:10px;
	left:10px;
	font-size:86px;
	color:#000;
	text-shadow:0px 0px 1px #fff;
	font-family:"Astloch", Arial, sans-serif;
	z-index:4;
}

The menu container will be placed absolutely to the left side of the screen:

.mb_menu{
	position:absolute;
	top:154px;
	left:0px;
	z-index:11;
}

The link elements inside of the menu container will be black boxes with a neat transition on hover:

.mb_menu a{
	background-color:#000;
	margin-bottom:2px;
	opacity:0.9;
	display:block;
	width:98px;
	height:98px;
	color:#fff;
	line-height:98px;
	text-align:center;
	text-transform:uppercase;
	outline:none;
	-webkit-transition: all 0.2s ease-in;
	-moz-transition:all 0.2s ease-in;
	-o-transition: all 0.2s ease-in;
	-transition: all 0.2s ease-in;
}
.mb_menu a:hover{
	color:#000;
	background-color:#fff;
}

Read more about transitions in the W3 working draft at http://www.w3.org/TR/css3-transitions/ or in this great article on A List Apart by Dan Cederholm: Understanding CSS3 Transitions.

Next step is to style the content wrapper. We will give it a fixed width and height and a semi-transparent dark background. We’ll hide it initially:

.mb_content_wrapper{
	background:transparent url(../images/bg_menu.png) repeat top left;
	width:400px;
	height:400px;
	position:absolute;
	top:154px;
	left:200px;
	z-index:4;
	display:none;
}

Why don’t we just use opacity instead of a repeated background image? In some browsers all child elements will inherit that opacity level and we cannot set it higher for them. So, if we really want the inner elements to be completely opaque, it’s safer to use a background image for the surrounding container.

The little closing span will have the following style:

span.mb_close{
	position:absolute;
	top:10px;
	right:10px;
	width:11px;
	height:12px;
	cursor:pointer;
	background:transparent url(../images/close.png) no-repeat top left;
	opacity:0.8;
}
span.mb_close:hover{
	opacity:1.0;
}

The content area is going to have some padding and we’ll hide it:

.mb_content{
	padding:30px;
	display:none;
}

The heading will have some background image for the stripe underline:

.mb_content h2{
	font-family:"Astloch";
	text-shadow:0px 0px 1px #fff;
	font-size:42px;
	background:transparent url(../images/line.png) repeat-x bottom left;
	padding:0px 0px 5px 0px;
	margin-bottom:10px;
}

The following container is for the resting content and it will be this element that we will apply the custom scrollbar to:

.mb_content_inner{
	line-height:24px;
	height:268px;
	outline: none;
}
.mb_content_inner p{
	padding:5px 0px;
}

For the thumbnail list in the “Work” section, we will have the following style:

ul.mb_imagelist li{
	float:left;
	margin:2px;
	cursor:pointer;
}
ul.mb_imagelist li img{
	display:block;
	opacity:0.3;
	-webkit-transition: all 0.5s ease-in-out;
	-moz-transition: all 0.5s ease-in-out;
	-o-transition: all 0.5s ease-in-out;
	-transition: all 0.5s ease-in-out;
}
ul.mb_imagelist li img:hover{
	opacity:1.0;
}

As you can see, we will add some transition to it, making the thumbnail become opaque smoothly.

And that’s all the main style. (You can check out the styling for the form and the footer in the style.css file.)

Let’s add some brio to the whole thing!

The JavaScript

So the main idea is to create those little boxes and scatter them around a restricted area and rotate them. When we click on a menu item, we’ll make those boxes animate to a certain position and form the main content container. Then we’ll show the container and the respective content. When clicking on the closing span, we want to make the boxes disperse again.
In the “Works” content, we will have some thumbnails that will show a background image when clicking on them.

So, let’s start by caching some elements:

var $menu				= $('#mb_menu'),
	$menuItems			= $menu.children('a'),
	$mbWrapper			= $('#mb_content_wrapper'),
	$mbClose			= $mbWrapper.children('.mb_close'),
	$mbContentItems		= $mbWrapper.children('.mb_content'),
	$mbContentInnerItems= $mbContentItems.children('.mb_content_inner');
	$mbPattern			= $('#mb_pattern'),
	$works				= $('#mb_imagelist > li'),
	$mb_bgimage			= $('#mb_background > img'),

Next, we will define the “Menu” function:

Menu		 		= (function(){
  ...
})();

/*
call the init method of Menu
 */
Menu.init();

So, inside of our “Menu” function, we’ll define our main functionality, starting with a method to initialize the whole thing:

var init			= function() {
	preloadImages();
	initPlugins();
	initPattern();
	initEventsHandler();
},

We want to preload the images that we have in the “Work” content. The data attribute in the thumbnails tells us, which images we need:

preloadImages		= function() {
	$works.each(function(i) {
		$('').attr('src' , $(this).children('img').data('bgimg'));
	});
},

The jScollPane plugin needs to be initialized, and we’ll apply the custom scroll to the inner content area of the content div when we call this:

initPlugins			= function() {
	$mbContentInnerItems.jScrollPane({
		verticalDragMinHeight: 40,
		verticalDragMaxHeight: 40
	});
},

“initPattern” will randomly place 16 boxes (div elements) into a restricted area. We restrict that area by restricting the top and left values to a certain range:

initPattern			= function() {
	for(var i = 0; i < 16 ; ++i) {
		//opacity, random top, left and angle
		var o		= 0.1,
		t		= Math.floor(Math.random()*196) + 5, // between 5 and 200
		l		= Math.floor(Math.random()*696) + 5, // between 5 and 700
		a		= Math.floor(Math.random()*101) - 50; // between -50 and 50
				
		$el		= $('
').css({ opacity : o, top : t + 'px', left : l + 'px' }); if (!$.browser.msie) $el.transform({'rotate' : a + 'deg'}); $el.appendTo($mbPattern); } $mbPattern.children().draggable(); //just for fun },

When we close the content area we want to move the little boxes back, scattered around randomly again:

disperse			= function() {
	$mbPattern.children().each(function(i) {
		var o			= 0.1,
		t			= Math.floor(Math.random()*196) + 5, 
		l			= Math.floor(Math.random()*696) + 5, 
		a			= Math.floor(Math.random()*101) - 50; 
		$el			= $(this),
		param		= {
			width	: '50px',
			height	: '50px',
			opacity	: o,
			top		: t + 'px',
			left	: l + 'px'
		};
				
		if (!$.browser.msie)
			param.rotate	= a + 'deg';
				
		$el.animate(param, 1000, 'easeOutExpo');
	});
},

Let’s handle the events:

initEventsHandler		= function() {
	/*
		click a link in the menu
	 */
	$menuItems.bind('click', function(e) {
		var $this	= $(this),
		pos		= $this.index(),
		speed	= $this.data('speed'),
		easing	= $this.data('easing');
		//if an item is not yet shown
		if(!$menu.data('open')){
			//if current animating return
			if($menu.data('moving')) return false;
			$menu.data('moving', true);
			$.when(openItem(pos, speed, easing)).done(function(){
				$menu.data({
					open	: true,
					moving	: false
				});
				showContentItem(pos);
				$mbPattern.children().fadeOut(500);
			});
		}
		else
			showContentItem(pos);
		return false;
	});
		
	/*
		click close makes the boxes animate to the top of the page
	 */
	$mbClose.bind('click', function(e) {
		$menu.data('open', false);
		/*
			if we would want to show the default image when we close:
			changeBGImage('images/default.jpg');
		 */
		$mbPattern.children().fadeIn(500, function() {
			$mbContentItems.hide();
			$mbWrapper.hide();
		});
			
		disperse();
		return false;
	});
		
	/*
		click an image from "Works" content item,
		displays the image on the background
	 */
	$works.bind('click', function(e) {
		var source	= $(this).children('img').data('bgimg');
		changeBGImage(source);
		return false;
	});
			
},

When we click on one of the thumbnails in the “Work” section, we want the background image to change. So we define:

changeBGImage			= function(img) {
	//if its the current one return
	if($mb_bgimage.attr('src') === img || $mb_bgimage.siblings('img').length > 0)
		return false;
				
	var $itemImage = $('<img src="'+img+'" alt="Background" class="mb_bgimage" style="display:none;"/>');
	$itemImage.insertBefore($mb_bgimage);
		
	$mb_bgimage.fadeOut(1000, function() {
		$(this).remove();
		$mb_bgimage = $itemImage;
	});
	$itemImage.fadeIn(1000);
},

This shows a content item when there is already one shown:

showContentItem			= function(pos) {
	$mbContentItems.hide();
	$mbWrapper.show();
	$mbContentItems.eq(pos).show().children('.mb_content_inner').jScrollPane();
},

“openItem” moves the boxes from the top to the center of the page, and shows the respective content item:

openItem				= function(pos, speed, easing) {
	return $.Deferred(
		function(dfd) {
			$mbPattern.children().each(function(i) {
				var $el			= $(this),
				param		= {
					width	: '100px',
					height	: '100px',
					top		: 154 + 100 * Math.floor(i/4),
					left	: 200 + 100 * (i%4),
					opacity	: 1
				};

				if (!$.browser.msie)
					param.rotate	= '0deg';

				$el.animate(param, speed, easing, dfd.resolve);
			});
		}
	).promise();
};

And that’s it! We really hope you enjoyed the tutorial and find it useful!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 76

Comments are closed.
  1. fantastic ! another great example of using jquery… awesome result, congratulations ! thanks for share and spread this works

    clap clap clap ! you rocks !

  2. Awesome! I really like the effect! I was looking for something similar but with Fliping effect while animating boxes but this is also a beautiful.
    Keep it up,you rocks!

  3. You guys just keep making my life easier and almost at the perfect time. Amazing result and really love the way you explain your code. Thank you so very much!

  4. It’s a nice effect. I have a suggestion. Currently when you click other menu, it just load its content. How about each menu item has different small squares with different colour? So that it will create another view. I hope it makes sense.

  5. beautiful post .. but I’m still confused .. whether this script can be used on blogspot or not …????

  6. nice! the only think I dont like is that this amazing animation of moving boxes is not there anymore after the first click ๐Ÿ™

  7. Hey, it’s really cool what you do with jquery. I have one question: what kind of filter do you use to get this effect on the photos? thanks a lot for sharing you code, I’ve learnt a lot.

  8. Hi there,

    Thank you for sharing this, I love it.
    Somebody knows if there is a possiblity to use lightbox insted of changing the background?
    Many thanks

  9. AMAZING
    Thanks for this one
    I can’t get the gallery (“work”) to work in IE
    The background doesn’t change ๐Ÿ™

    What am I doing wrong??

    Peace

  10. Thanks so much. You have produced some fantastic easy to follow tutorials Mary Lou. Are you on twitter?

  11. This is amazing Mary Lou!!! I was wondering if you could show us how to switch the gallery into a lightbox gallery instead of changing the background? thanks!!

  12. Hi there… Please forgive me if I sound stupid, bud I downloaded a .zip files and it is not working. I guess I’m not experieced enough to fix it myself, so please, could you give me some tips, where the error could be?

  13. When I’m hovering mouse over the menu, it changes color, but when I click it, nothing happens. Please feel free to write me an email on jantio@centrum.cz, this is awesome and I wish to use it as a gallery for my photos.

  14. WOW! This is great!
    Is it OK to download it and use some part of code to design my own website?

  15. Hey everyone!! any chance someone can help me out with turning the photo thumbnails into a lightbox gallery? I would deeply appreciate it!

    thank you!!!

  16. @ALE — have you made a lightbox gallery of any sort before? just so that i know where to start w/ you.

    @MARY LOU — do you have example code for the php/form? i have never styled a php form with css before and don’t know where to add the name/ids.

  17. one question, i realized you achieved a liquid layout, what i used to do a lot in flash, keeping the background always at 100% size.. but keeping the image proportions.. i am trying to achieve the same with css but cant find a way to keep the aspect ratio.. ๐Ÿ™ how did you do it?

    btw awesome post!! thank you so much!!

  18. @anya โ€“ thanks for reaching out! no, I haven’t done the lightbox yet. Usually I would just install one taken from the web. I don’t really know how to program, so I have no idea how to change the coding to turn it into a lightbox. Any chance you could help out? thanks!!! =-)

  19. the lightbox i like to use is this one: http://leandrovieira.com/projects/jquery/lightbox/

    there are some very straightforward instructions on the site, but before you begin, make a copy of your site with no other scripts running and test it there — this way you know the plugin works before you run into a language conflict [this sometimes happens on sites with lots of jquery/javascripts] running.

    you may have succesfully used it before and not even known it because it may have been stopped by other scripts on your site.

    ALSO, be very careful how you link to and structure your files.

    for example, the first step is to include the js files in your header.

    so, your file structure should have the index.html file in the root structure and the js files in a folder titled js.

    feel free to send me your code & i’ll take a look at it.

  20. Wow, your awesome!!! Thanks for the cool and very well written tutorial. The community thanks you!!!

  21. i am rrraaaaacking my brain trying to figure out how to get the first content set to open by default. =(

  22. Hello! Great tutorial! I have a question, how would you extend the menu buttons such as “about” to use a longer phrase; something like “check me out on facebook”