Creating equal-height columns with CSS is sometimes a bear. But who needs the hassle of faux columns, “clear” divs and the rest? With this bit of jQuery, you can easily equalize the heights of any group of elements.
This technique was born of frustration. I ran into two layout problems while working on the redesign of CSS Newbie one afternoon, and both were directly related to the varying heights of elements.
The first problem was in the footer. If you look closely, you’ll see that there is a nice subtle two-tone border in between each of the columns in the footer.

That style wasn’t as easy to create as it might look. At first, I was going to make the border part of the background image, and just edit my content to suit. But that’s very un-web of me: the beauty of the web is we’re not constrained by sizes nearly as much as print designers.
So instead, I decided to make the borders the old-fashioned way, as legitimate CSS borders. Of course, to get it exactly the way I wanted I had to resort to a bit of a hack, matching light borders on the right side of one column with a dark border on the left side of the following column. The hack works beautifully… as long as all three of my columns are of equal height. Otherwise, the borders don’t match:

The second problem I ran into was in the “recent articles” section of the homepage. I wanted to feature four articles, but I didn’t want them to take up a ton of space. To accomplish that, I made the article blocks half as wide as my space and floated them into two columns with two rows.
And as long as I’m lucky and all my excerpts are the same length, that works fine. But the instant something is a line or two longer or shorter, one of the more annoying flaws with floats rears its ugly head. If I have a long excerpt in spot 1, followed by a short excerpt in spot 2, the excerpt in spot 3 won’t float all the way to the left: it’ll get caught on the edge of the first excerpt instead.

So again, I have a height-related problem. “If only there was an easy way to equalize heights without resorting to a table,” I thought thusly.
And so I set out to find an easy way. And after a bit of fiddling with jQuery, I was able to find a workable solution. Here’s the function I ended up with:
function equalHeight(group) {
tallest = 0;
group.each(function() {
thisHeight = $(this).height();
if(thisHeight > tallest) {
tallest = thisHeight;
}
});
group.height(tallest);
}
You can see it in action here. What this function is doing is:
- Sets a variable, “tallest,” to zero.
- Loops through each of the items in the group we’ve defined.
- If the current item is taller then the previous “tallest” item, it becomes the new tallest item.
- Once we’ve looked at all the items, they all get their height reset to be the same as the tallest of the group.
So in order to equalize the heights of both my footer columns and my recent articles, all I needed to do was something like this:
$(document).ready(function() {
equalHeight($(".recent-article"));
equalHeight($(".footer-col"));
});
Which just waits until all my elements are done loading (so that the heights can be computed accurately), then sets both the heights.
That’s all there is to it! This function is good for fixing wily floats without clears, creating nice equal-height column designs without needing faux columns, and probably half a dozen things I haven’t thought of yet. I’m sure you’ll be able to find a use for the script someday… after all, I managed to find two uses in a single afternoon!



On December 07, 2008
5:06PM
Bram Van der Sype said:
That’s a very handy thing you’ve got there. A while back (when I just started CSS) I believed in the “all things css, no javascript whatsoever” ideology. I soon found out creating equal height columns with pure CSS was a bitch.
I found a piece of javascript that worked brilliantly, but it was quite long. Now, with some jQuery love, it’s easy to do.
Thanks!
On December 08, 2008
10:16AM
Joe McCann said:
Nice, but what happens when JS is turned off?
On December 08, 2008
10:25AM
Steph Adamo said:
I’m pretty excited to use this, but i’ve never used jquery before so i’m admittedly pretty ignorant about how it works. Won’t i need the jquery.js file in order to implement it?
On December 08, 2008
10:45AM
Rob Glazebrook said:
@Bram: Thanks! I’m hoping it will be helpful to people.
@Joe: Without JS, your columns/boxes/whatever will look exactly as they would have looked before you found this lovely script. :) The idea is, get your columns close with CSS, and then perfect them with JS. However, I’d really think that the vast majority of people would be running JavaScript these days. Too many websites use it to ignore on purpose…
@Steph Yeah, you’d need the jquery.js file as well as this script. Basically, you run jQuery first:
<script src=”jquery.js”></script>
Then below that, you’d put this function inside its own <script> tag.
On December 08, 2008
3:43PM
Ben Reimers said:
Very handy! I’ve just been getting into jQuery and have been following handy little hints like this closely. It’s a pity something like this isn’t simply a part of CSS, but that’s the Internet. Thanks for sharing.
On December 09, 2008
7:13PM
jaredmellentine said:
I had just written a jQuery function for this last week. I run the function on all the children of a parent container (passed through the jQuery object). Other than that, we wrote our functions about the same. But here’s mine anyway:
(function(jQuery) {
jQuery.fn.equalHeights = function() {
var maxheight = 0;
jQuery(this).children().each(function(){
maxheight = (jQuery(this).height() > maxheight) ? jQuery(this).height() : maxheight;
});
jQuery(this).children().css(’height’, maxheight);
}
})(jQuery);
You could extend it a bit more to give a minimum height, too:
(function(jQuery) {
jQuery.fn.equalHeights = function(minheight) {
var maxheight = minheight || 0;
jQuery(this).children().each(function(){
maxheight = (jQuery(this).height() > maxheight) ? jQuery(this).height() : maxheight;
});
jQuery(this).children().css(’height’, maxheight);
}
})(jQuery);
On December 09, 2008
7:20PM
jaredmellentine said:
I forgot to mention how you would call the function:
jQuery(’#mycontainer’).equalHeights();
Or with a minimum height of 300px:
jQuery(’#mycontainer’).equalHeights(300);
On December 10, 2008
11:26AM
Chris Raymond said:
In your example, if you resize text only, the columns do not stay equal in height (well, the backgrounds do, but the text overflows under the boxes)
On December 10, 2008
3:48PM
Rob Glazebrook said:
@jaredmellentine: D’oh! You beat me to it. I was planning on releasing a plugin based on this script yet this week! Actually, I may still… our functions are technically a little different. However, you’ve given me some good ideas for how I can extend the function I’ve written. Thanks!
On December 10, 2008
5:57PM
Grant Palin said:
This is very timely, as I am working on a new theme and was needing some equal-height columns. So simple, yet so useful.
@Chris Raymond: I have noticed this too. But if you refresh the browser window, the columns will be redrawn to contain the text. In Firefox anyway…The same applies for sizing text smaller, the columns will not automatically shrink.
On December 11, 2008
12:45AM
jaredmellentine said:
@Chris and Grant: I guess it’s about time someone write a jQuery event handler for text zoom.
http://design.mellentine.com/2008/12/11/javascript-the-start-of-a-jquery-zoom-event-handler/
On December 11, 2008
3:05PM
Phil said:
Could this be used on grouped columns, so each box is only adjusted to others in the same ‘row’?
I toyed around with a loop function but being a jQuery novice, couldn’t quite get my head around it!
On December 11, 2008
6:46PM
jaredmellentine said:
I finished the jQuery zoom plugin, which may help the issue brought up by Chris. You can check it out here: http://www.dzone.com/links/zoom_event_handling_with_jquery_plugin_demo.html
@Rob: The more I think about this, maybe using the min-height CSS property instead of height would help this issue as well. It wouldn’t keep the columns the same height if you zoomed in, but it should (in browsers that support min-height) extend the container so that the text doesn’t flow out of it.
On December 13, 2008
12:05PM
Rob Glazebrook said:
@Jared: Thanks for the plugin! I’ll be trying it out. Although I’m not sure I agree with using min-height as a workaround. I understand that would fix the overflow property. But as soon as I switch to using min-height, I have an equalHeights plugin that no longer guarantees equal height elements. That seems counterintuitive to me.
On December 13, 2008
9:41PM
jaredmellentine said:
@Rob: I’ve just never been a fan of overflow: auto, except for specific cases. It’s a designer preference to have extra scrollbars or to have containers that don’t line up. I prefer fewer scrollbars because it means that my content is visible without an extra scroll, and I just think it’s a better user experience. Neither solution is ideal. I guess the best way to handle this would be to have some sort of zoom event handler. =)
Most importantly, this issue (zooming that breaks layout) is an infrequent issue. Not only that, but it would be resolved the next time the page loads. It may just be a moot point.
On December 17, 2008
11:38PM
Richard said:
Your example shows that it works very nicely in FireFox (3.x Mac).
Not so much in Safari (Mac). Not sure why, but I do notice that it fits in the default font size, but as I increase font size the text runs down through the bottom of columns [and: width of entire containing area does NOT expand - which it does in FireFox (both horiz & vert)].
Also, I’m wondering if your approach works with various settings for WIDTH of div: since FF wants to expand it as type size grows & Safari does not. Might be worth testing re: what varieties of style respond well (fixed-width; fluid; flexible; %, etc)
It’s a challenging problem: hats off to you for introducing a new approach!
On January 21, 2009
1:39AM
Sedat Kumcu said:
Thanhs thanx thanx maan. Useful and very easy method and understandable article. ;)
On February 11, 2009
9:43PM
Sarah said:
I’m using your script with mixed success. On some pages I have it running on two columns and it seems to work fine. However, I am also trying to run it on a page with four columns (using a separate class name) and it seems that about 3 out of every 5 random refreshes it will calculate the height incorrectly, resulting in the four columns overlapping whatever is underneath. Any suggestions? Is there any way to tell the script to wait until the document is ready, then wait an additional couple of milliseconds?
On March 19, 2009
11:53AM
Kevin Rapley said:
This is a lovely script and will work really nicely with a layout based on widths in em sizes that has to be seriously hacked in order to get a background image or other means to work when the text size is increased/decreased. However if you’re looking to keep fixed width columns in px sizes then I would recommend using a background image to give the illusion. If JavasScript is disabled in a user’s browser the columns not aligning break the design which is just not good enough. It has to align at the bottom of the columns regardless of platform and technology. I don’t think a small amount of CSS telling the background to repeat on a y-axis ever hurt anyone.
On April 20, 2009
11:37PM
SohoInteractive said:
works consistently on all browsers. Thank you for sharing.
K.
On April 27, 2009
3:18PM
Eric Sender said:
You’re a genius, thanks!
On April 30, 2009
4:54AM
Alexandru Dinulescu said:
Hello.
I think you are doing something very wrong with that $(document).ready() part. Since what you do is you put each variable separately instead of them together, so if you look at how the initial function is built, in the document ready you assign each variable to a DIFFERENT instance of the initial function instead of passing all the values through 1 function.
For Ex:
$(document).ready(function() {
equalHeight($(”.recent-article”));
equalHeight($(”.footer-col”));
});
these 2 values are independent from one another, so nothing will be compared between them. first the equalHeight function parses the recent article value, and then it passes the footer-col value but it doesnt compare it. This happened to me today while i was struggling to see why it doesnt work and it just hit me.
In order to make it work you have to make it like this
$(document).ready(function(){
equalHeight($(”#left, #center, #right”));
})
because there is only 1 INSTANCE of the equalHeight, and all the variables are separated by commas. Each function from what i can remember separates the values by commas. Now the function will work 100%.
It may be an oversight but i tested it and this is the result i came across.
Best Regards
AlexD
On April 30, 2009
9:33AM
Rob Glazebrook said:
Hi Alexandru,
You’re right — if you want to compare two items/groups and equalize heights across them, you’d want to include them in a comma-delimited list like you have in your example.
My example was looking at a slightly different use-case. In my example, I had two different groups of columns that needed to be equal heights.
In my example, my “.recent-article” was class applied to four divs, and my “.footer-col” class applied to three divs. I needed all the recent articles to be the same size, and all the footer columns to be the same size, but I didn’t want or need my recent articles to be the same size as my footer columns. So I called the two groups of columns independently, running the function twice.
So to clarify, if you call the function twice, nothing will be compared between the two instances. This may or may not be what you are looking for. :)
On April 30, 2009
10:24AM
Alexandru Dinulescu said:
Hello.
Yes i presumed as much however you may want to edit your blog and place this bit of information in it, because most people who read this arent very proeficient in jQUery and they may just see what you did there and try to emulate that using the method you had applied and making them like that.
My opinion at least.
However it’s a good thing, i’ve used something very similiraly for quite a while and i just realized when i read this topic what the issue actually was.
On May 08, 2009
6:58AM
Jeff said:
@Rob - Thanks for the script! Although I am having trouble with it. I know very little about JS and jQuery, so I’m not the best person to troubleshoot it. I’ve got a page that’s about a 300k load. When I clear my cache and load it the first time, the script calculates well short of the highest column height and then breaks the layout by shortening both columns too much. If I hit refresh, it works beautifully. So it seems like there’s an issue with it not getting all the elements on the page loaded. I wish I could show you an example but I’m developing NDA stuff on an internal network, so…
On May 08, 2009
7:32AM
Rob Glazebrook said:
Hi Jeff,
You might need to wait until the page has completely loaded before firing the script. The easiest way to do that is instead of enclosing the entire thing in this:
$(document).ready(function() {…everything here… });
Try using this instead:
$(window).load(function() { …everything here… });
The downside to this is your columns won’t adjust until everything else on the page has loaded. The upside is, your columns should be the same size.
On May 08, 2009
7:45AM
Jeff said:
Excellent. Works like a charm.
I figured it was something with the page loading, but I didn’t know how to delay the calculation (like I said, I know next to nothing about JS).
Thanks so much for your help!
On May 16, 2009
6:28PM
richard said:
Found this very useful, worked it into a theme, thanks!
On June 04, 2009
8:22AM
Paul Boutin said:
What happens if you have images in your columns?
In jQuery running this function in the ready state of the document is before images are loaded and their heights will not be taken into account. Once the images load your column heights will no longer be equal.
On June 04, 2009
8:44AM
Rob Glazebrook said:
Hi Paul,
That is true — images can cause the script some problems. There are two known (and relatively simple) ways around this problem.
1. Instead of running the script within $(document).ready(), run it in a $(window).load() instead. Whereas document ready fires as soon as all the code is done downloading (but possibly before the images have finished), window load doesn’t fire until even the images are downloaded, allowing the script to make more accurate calculations.
2. If you set a height attribute on your images, that height is used when calculating the overall column height, thus getting around the problem. I realize that width and height aren’t really recommended on images anymore (I’m pretty sure they’re deprecated in XHTML), but I’m personally fond of them and still use them — it prevents your content from re-wrapping once your images have downloaded.
Enjoy!
On June 08, 2009
12:30PM
Ben said:
Awesome, solved a big issue with our new website design.
Thanks a Ton!