
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…
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.
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
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>
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();
});
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)
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.

Discussion
Wow, i will try this now, thanks for a great tut.
Thanks mate. I forgot to put up a link to the demo page. But here’s anyway if you wanna try it out:
http://rtherianto.net/toolbox/fluidgrid/index.html
Thanks sam
I have edited the post to include the demo link Rendian, thanks gain for letting me post this on CreativityDen!
Nice tutorial. People looking at this might like the jquery masonary plugin – http://desandro.com/resources/jquery-masonry
Really interesting. But is there a way to generate grids with auto size, eg.: with percentage?
@Mustafa: Yes indeed, Masonry from David is what I meant with ‘more advance’ version of grid-based layout. This tutorial is merely to give the basic idea of how it works.
@Carlos: I’m not sure it’ll work with percentage. Because if you’re using percentage, then resizing the window will only shrink or enlarge the column. But the column number will remain the same. If that’s the effect that you want, it’s still possible though, with a slightly different algorithm of course
Great tutorial Rendian. I have been trying to accomplish something similar in this project that I was working on about a month ago. I wish I had this guide then. It gave me quite a headach.
I think you can also do it using a and CSS without any javascript
and then probably use a small jquery function to do alternate colors
here’s an example
$(‘li:odd’).addClass(‘alternate’);
.SplitColumns li
{
float: left;
width: 15%;
text-align:left;
margin-left:.1em;
padding:.2em;
padding-left:.5em;
background-color:#efefef;
margin-bottom:.1em;
}
sorry the HTML in my comment above got parsed. basically what i was trying to say is you can use an unordered list UL and CSS class to do something similar to your tutorial
Thanks Liam,
Rendian, just try using this code
<script src="jquery/jquery-1.3.2.min.js" type="text/javascript"></script> <script language="javascript" type="text/javascript"> $(document).ready(function() { $('li:odd').addClass('alternate'); }); </script> <style type="text/css"> .SplitColumns li { float: left; width: 15%; text-align:left; margin-left:.1em; padding:.2em; padding-left:.5em; background-color:#efefef; margin-bottom:.1em; } .alternate { background-color:#ffffff !important; } </style> <body> <ul class="SplitColumns"> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> <li>kjhsdkfjhsdkfjh ksdjfh skdjfhsdkjfhskdjfhkjsdh ksdjh fskdjfh skdjhf ksjdhf kshf</li> </ul> </body>superrrr html code
@design informer: thanks!
@abhijeet: By using float alone, I can already see that you will have a lot of vertical gaps between boxes especially if each box has different height. Also using percentage as column width will eliminate the concept of fluidity, as the column number will always be the same. Have you try the demo…
Rendian, that’s a good point. yes the CSS solution will work if the height of LI is equal.
Thanks for sharing this cool toturial!
Keep it up, dude~
.-= 10V´s last blog ..给大家推荐一个PHP网站地图生成类 =-.
Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!
Thank you very much for the kind words. New articles will be better yet
Nice tutorijal, I’ll try to use some of the tips in redesign of my own web
Wondering what this would look like, and work in practice, with a larger variance in lengths of the box items.
In particular the prospect of one column ending-up much longer than the others may significantly muddy the aesthetics.
The end result looks quite nice and clean. Very nice use of jQuery for content layout.
First Fluid CSS Grid I’ve seen to rival Soh Tanaka’s http://j.mp/T1vgT . Great work. Have been working through one that uses HTML5 elements. I’ll post a link when complete. Thanks.
hey guys I can’t see it right in safari :S
do anyone knows why?
Well, unless javascript is disabled, the demo page should work just fine in any modern browsers…
Good job!!
Nice job. Is there any chance to margin whole site for one column so i could easily insert one normal div. If i do it with margin whole site gets horizontal scroller. Thanks for helping me out.
@Roman: Not sure I understand with what you want to achieve. But if you want some more margin in the body so that the boxes didn’t start at top 0 and left 0, there are 2 ways to do it.
1. Remove width 100% from body style, and add margin (e.g. 10px).
2. Add margin directly on the boxes (e.g. put 10px margin in the .box class).
Haven’t tested it, but it should do the trick.
Thankyou very much, it works. I don’t know how i missed it. It work now super cool. Thanks again.
thanks admin
I notice that the thumbnails on the pages are often cropped when first loaded and need to be recalibrated by hitting command + and – . Is there a way so that this doesn’t happen and that it will show the correct thumbnails?
Its perfect tut.. Thanks for sharing!
how do i avoid the thumbnails getting cut off? when i hit Command + and – it recalibrates, but i’d prefer that the thumbnails load to their proper size initially…
thanks,buddy…looking forward to your new posts
Hey, This looks great but I’ve been working with it all morning and I haven’t been able to get it to work within a wrapper I’d love to use this on a site but need it to work ONLY in the main body of the site (not the whole page). Any idea on the modification I’m missing to make that happen? If there was another example provide here that would be great!
Thanx for information..
nice tutorial
Leave a comment