How to create a fluid grid with jQuery

Fluid Design

Grid-based layout is probably the more preferred way to style up a webpage to give it more magazine-like look and feel. This tutorial is about how to use CSS and Javascript to create a fluid grid-based layout (See demo here). The algorithm/procedure used in this tutorial is very simple and straightforward. There are more advanced algorithms out there which can handle multiple scenarios. But the purpose is to understand the basic logic on how to create such layout. So here it goes…

Step 1: Preparing the HTML

First we need to create a basic HTML structure. Here’s one example:

<html>
	<head>
		<title>Fluid grid</title>
		<script type="text/javascript" src="script/jquery-1.3.2.min.js"></script>
	</head>
	<body>
		<div class="box"><p><span>01</span>This is box number 1...</p></div>
		<div class="box alt"><p><span>02</span>This is box number 2...</p></div>
		<div class="box"><p><span>03</span>This is box number 3...</p></div>
		<div class="box alt"><p><span>04</span>This is box number 4...</p></div>
		<div class="box"><p><span>05</span>This is box number 5...</p></div>
		<div class="box alt"><p><span>06</span>This is box number 6...</p></div>
		<div class="box"><p><span>07</span>This is box number 7...</p></div>
		<div class="box alt"><p><span>08</span>This is box number 8...</p></div>
		<div class="box"><p><span>09</span>This is box number 9...</p></div>
	</body>
</html>

The divs will be our items, articles, posts, or whatever you call it.

For better understanding of the layout, it is recommended to replace the sample text ‘This is box number…’ with a longer one. Preferably varies in length between one box to another. The illustration images in this tutorial will be using randomly generated text for the box content.

Step 2: Style up a little bit

Then for each step, just write some text describing the step and provide an image which is less than 600px wide.

<link rel="stylesheet" type="text/css" href="style/reset.css" />
<style type="text/css">
	body {
		position: relative;
		width: 100%;
	}
	.box {
		background-color: #F0F0F0;
		color: #888;
		font-family: Arial, Tahoma, serif;
		font-size: 13px;
	}
	.box p {
				padding: 10px;
			}
	.box span {
		float: left;
		font-size: 26px;
		font-weight: bold;
	}
	div.alt {
		background-color: #CCC;
	}
</style>

At this point, the page will look like this:

With no jQuery

Step 3: The Javascript

3.1: The attributes

For the sake of usability, we will create a namespace to avoid conflicts with other scripts/libraries using the same variable names. Let’s use myFluidGrid as our namespace:

<script type="text/javascript">
	var myFluidGrid = {
		COLNUMBER : 2, // Minimum column number.
		COLMARGIN : 10, // Margin (in pixel) between columns/boxes.
		COLWIDTH : 240 // Fixed width of all columns.
	};
</script>

3.2: The method

doLayout : function() {
	var self = this;
	var pointer = 0;
	var arr = [];
	var columns = Math.max(this.COLNUMBER, parseInt($('body').innerWidth() / (this.COLWIDTH + this.COLMARGIN)));

	$('.box').css('position', 'absolute').css('width', this.COLWIDTH  + 'px');
	$('.box').each(function() {
		var tempLeft = (pointer * (self.COLWIDTH + self.COLMARGIN));
		$(this).css('left', tempLeft + 'px');

		var tempTop = 0;
		if (arr[pointer]) { tempTop = arr[pointer];	}
		$(this).css('top', tempTop + 'px');

		arr[pointer] = tempTop + $(this).outerHeight() + self.COLMARGIN;
		pointer++;
		if (pointer === columns) { pointer = 0; }
	});
}

What we do here is basically we grab all boxes and set their width value with the default setting (COLWIDTH). Then we do an iteration to process each boxes.

Inside the loop, we calculate the new left and top position for each box. Defining the left position is easy using the pointer variable. Pointer is our current column position. Just multiply pointer with the box’s width (plus margin). Don’t forget to increase pointer at the end of each iteration (or reset it when it reaches the maximum column number).

Setting the top position is the tricky one. That’s where arr variable comes in handy. It basically stores the bottom position of the last box put on each column. For example: if we put box 1 in column 1 with left=0 and top=0, and box 1 has 80px height. Then arr[0] will be 80 + box margin. This arr[0] is then used as a top position for the box under box 1. See illustration below for details:

Calculating positions

At this point the value of arr will be [0]=>(80 + box margin), [1]=>(69 + margin), [2]=>(81 + margin). The next box (box 4) will use arr[0] as its top position. And it goes on until the very last box.

Finally, we attach doLayout function to window onload and onresize event using this piece of code:

$(window).ready(function() {
	myFluidGrid.doLayout();
}).resize(function() {
	myFluidGrid.doLayout();
});

Step 4: Putting it all together

Here’s the final code:

<html>
	<head>
		<title>Fluid grid</title>
		<link rel="stylesheet" type="text/css" href="style/reset.css" />
		<style type="text/css">
			body {
				position: relative;
				width: 100%;
			}
			.box {
				background-color: #F0F0F0;
				color: #888;
				font-family: Arial, Tahoma, serif;
				font-size: 13px;
			}
			.box p {
				padding: 10px;
			}
			.box span {
				float: left;
				font-size: 26px;
				font-weight: bold;
			}
			div.alt {
				background-color: #CCC;
			}
		</style>
		<script type="text/javascript" src="script/jquery-1.3.2.min.js"></script>
		<script type="text/javascript">
			var myFluidGrid = {
				COLNUMBER : 2, // Minimum column number.
				COLMARGIN : 10, // Margin (in pixel) between columns/boxes.
				COLWIDTH : 240, // Fixed width of all columns.
				doLayout : function() {
					var self = this;
					var pointer = 0;
					var arr = [];
					var columns = Math.max(this.COLNUMBER, parseInt($('body').innerWidth() / (this.COLWIDTH + this.COLMARGIN)));

					$('.box').css('position', 'absolute').css('width', this.COLWIDTH  + 'px');
					$('.box').each(function() {
						var tempLeft = (pointer * (self.COLWIDTH + self.COLMARGIN));
						$(this).css('left', tempLeft + 'px');

						var tempTop = 0;
						if (arr[pointer]) { tempTop = arr[pointer];	}
						$(this).css('top', tempTop + 'px');

						arr[pointer] = tempTop + $(this).outerHeight() + self.COLMARGIN;
						pointer++;
						if (pointer === columns) { pointer = 0; }
					});
				}
			};
			$(window).ready(function() {
				myFluidGrid.doLayout();
			}).resize(function() {
				myFluidGrid.doLayout();
			});
		</script>
	</head>
	<body>
		<div class="box"><p><span>01</span>This is box number 1...</p></div>
		<div class="box alt"><p><span>02</span>This is box number 2...</p></div>
		<div class="box"><p><span>03</span>This is box number 3...</p></div>
		<div class="box alt"><p><span>04</span>This is box number 4...</p></div>
		<div class="box"><p><span>05</span>This is box number 5...</p></div>
		<div class="box alt"><p><span>06</span>This is box number 6...</p></div>
		<div class="box"><p><span>07</span>This is box number 7...</p></div>
		<div class="box alt"><p><span>08</span>This is box number 8...</p></div>
		<div class="box"><p><span>09</span>This is box number 9...</p></div>
	</body>
</html>

At the end, your page will look pretty much like this illustration below: (try resizing the browser window to see how the fluidity works)

Demo

End result, nice and fluid!

Final words

Hopefully this tutorial will give you better understanding on how to create a very simple fluid grid layout. Later on you can make modification such as using dynamic box width instead of static. That’s it for now. Any suggestions, comments, and critics are welcomed.

  

Written by Rendian Therianto

Rendian Therianto is a web developer and designer based in Amsterdam. Aside of his fulltime job, he also does small to medium freelance projects. Find him on his website, blog, or twitter.

Subscribe!

Discussion

Leave a comment