Setting Equal Heights with jQuery

Posted by Maggie and Scott on 07/25/2008

Topics:

We wrote a script to "equalize" the heights of boxes within the same container and create a tidy grid — with little overhead.

Creating the visual effect of equal-height columns or content boxes has been a challenge ever since we abandoned table-based layouts. When developing complex web applications or site designs we've found that it often makes the most sense from a usability and performance standpoint to use a simple JavaScript workaround: our equalHeights() function determines the heights of all sibling elements in a container, and then sets each element's minimum height to that of the tallest element. When JavaScript is disabled, the boxes or columns appear with varying heights, but the content remains legible and the page is still completely usable.

Why not just use CSS?

We advocate using CSS whenever possible, and we often can because there are many clever ways to create the illusion of equal-height boxes without resorting to setting a fixed height, like Dan Cederholm's faux columns. This and similar techniques are great for columns in a page layout, but they don't translate very well when we're building, say, a web application dashboard page where 4 small widget boxes sit in a "row." In this case we could create an uber tiling background image that has backgrounds for 4 columns, but we'd also have to design the boxes with square corners (or make a big sliding door), fix the widths of each box, and make sure the markup lines up exactly with the background image. Or, because CSS2 only supports one background image per element, we could nest 4 separate divs, each with it's own positioned background image. No matter how we approach it, we've yet to come across a CSS-only solution to this use case that doesn't require pixel-exact calculations when creating the background images, or a significant amount of unnecessary markup. Let's not even discuss what you have to do when the boxes can vary in width, too.

JavaScript to the rescue

Calling equalHeights() on DOM ready let's us keep all of the important factors in play, without adding extra markup or complex CSS workarounds:

  • usability. This is strictly a visual effect, so when the script is absent, columns are of varying heights and the page remains totally usable.
  • layout flexibility. The script assigns a min-height value (not height), so when content is added through user interaction or via AJAX running in the background, or if the user increases the browser text size, the content box will grow to fit. Columns or boxes can keep their percentage or em-based widths.
  • performance. It's lightweight — has a small footprint, and doesn't insert any DOM elements or require extra markup — and unobtrusive because, like other jQuery plugins, it's called on standard CSS selectors.

How it works

equalHeights() loops through the top-level child nodes of a specified element and sets their min-height values to that of the tallest. It's set up as a standard jQuery plugin, and is called on the container element:

$('.container').equalHeights();

In our version of the script the default unit is set to ems so that the content boxes will scale. This requires another of our methods, pxToEm; if it's not present, the default unit reverts to pixels. Or, if you're using pxToEm, you can override the default and pass a "true" argument to set the unit in pixels.

Demo page

Download (and help us improve) the code

This code is open source and available in a git repository, jQuery-Equal-Heights. If you think you can help on a particular issue, please submit a pull request and we'll review it as soon as possible.

Book cover: Designing with Progressive Enhancement

Enjoy our blog? You'll love our book.

For info and ordering: Visit the book site

Comments

This is great! I actually have an immediate use for this technique.

Comment by Nosredna on 07/25  at  09:13 PM

We were in the process of writing a script to do this so f-ing thanks!

This should make the perfect study on how to turn some tacked-on code into an actual plug-in.

( one next step might be to get this into the tabs UI component as the default behavior )

Comment by Scott Fitchet on 07/25  at  09:28 PM

I published a similar script a while back. My script takes an arbritrary collection of elements, rather than acting on top-level children of a container element. I think your use case is by far the most common, but I recently had a need to equalize elements that didn’t have a common parent.

I recently updated my demo page using my new “onfontresize” custom event script to ensure that the element heights are re-equalized when the user resizes her fonts.

http://tomdeater.com/jquery/equalize_columns/

Comment by Tom Deater on 07/28  at  08:19 PM

nice, Ill give a try now, thanks for sharing

Comment by acms on 08/02  at  10:00 PM

Is it possible to resize the elements after text has been resized in a browser?

Comment by Andrew Care on 08/17  at  01:12 AM

Despite this:
and sets their min-height to the tallest height (or width to widest width). Sets in em units by default if pxToEm() method is available.

I can’t figure if it’s already set in em unit because when I enlarge font-size, I am getting unequal height.
With ‘true em unit’ you will always get the same ‘equal height’.

Nice though.

Comment by sutra on 09/19  at  03:15 PM

Perhaps you should check out my nested container equal height columns with pure CSS, these should do everything you need without the JavaScript.

Comment by Matthew James Taylor on 10/25  at  05:23 AM

@Matthew James Taylor:

I like your solution, however the problem with it is that not all CMS systems can spit out HTML in that sort of way. Some will only generate content per object, and therefore you can’t predict - ahead of time, how many containers you will have. The best you can do is to spit the objects out and wrap them in a common element (the .container).

This solution really solves that problem, since you can spit out an x-number of containers, and then toggle the JS over all those containers for them to equalize.

Comment by Anton Babushkin on 11/10  at  02:53 AM

This works great.  I had grid of floated div’s that I wanted to fill a dynamic width then wrap. Unfortunately the wrapping was occassionally out of wack if the heights varied just slightly, not anymore. Nicely done, and much thanks!

Comment by Inlime on 11/19  at  03:45 AM

When browser checking on firefox 2.0.0.17 I did find some odd behavior. While this may only be related to the way I am using it, I thought I’d share that changing lines 29:30 to the following fixed my issue:

jQuery(this).children("div").css({ “height” : currentTallest, “min-height” : currentTallest });

From what it seems it didn’t like children() without an element.

Comment by Inlime on 11/19  at  05:26 PM

Your script doesn’t work in my IE 6.

A,C & D are equal but B is taller.

Comment by Al on 11/22  at  01:55 AM

This is awesome. Is there a way to make this work with rounded corners? How about with borders AND rounded corners?

Comment by Patrick Elward on 01/18  at  10:13 PM

Nice!

Comment by longstep on 01/19  at  11:16 AM

This is cool.  Can it be made to act on certain classes rather than all children of and element?

Comment by velocitykendal on 01/22  at  06:03 PM

Great!!! Will try this

Comment by dsignz media on 02/09  at  01:13 PM

I was having issues with the script starting before the images were loaded and so the min-height that got calculated was wrong.  This is what I did to fix it:

$(function(){
if ($(’img’).length) {
$(’img’).load(function() {
$(’#column_wrap’).equalHeights();
});
} else {
$(’#column_wrap’).equalHeights();
}
});

Comment by Nate on 02/10  at  02:09 AM

Great little script.
Very useful! Thank you

Comment by Omdu on 02/10  at  11:03 PM

Thanks for the work - having an issue in Google Chrome though - it’s making the columns equal height, but there’s added padding. I assume it’s not calculating the height correctly?

Comment by chief on 02/16  at  11:08 PM

I find this script very useful, but it has an important issue:  It assumes that the elements share the same padding size.

I had to change height() by innerHeight() when getting the currentTallest:

$(this).children().each(function(i){

__if($(this).innerHeight() > currentTallest) {
____currentTallest = $(this).innerHeight();
__}

});

And then change children with an each(), to check each one’s padding before setting it’s height.

var cssname = ‘min-height’;

if ($.browser.msie && (ie6)) { cssname = ‘height’; }

$(this).children().each(function(i){

__$(this).height(currentTallest -
_______________($(this).innerHeight() - $(this).height()));

});

If you’d like to include the borders too, then you should change innerheight with outerheight.

Comment by hernan on 03/12  at  05:22 PM

Very nice job!
I just had a problem, line 24: if (!px || !Number.prototype.pxToEm) currentTallest = currentTallest.pxToEm(); //use ems unless px is specified…
Just commented that and worked fine.

Comment by Vinicius Borriello on 03/25  at  05:44 PM

@Vinicius Borriello:  Thanks!  By the way, line 24 may have been causing you trouble if you didn’t also have the pxToEm() function available.  It’s a little script we developed to convert units from pixels to ems (and vice versa) when resizing components on a page, etc.  More information here: 
http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/

Comment by Maggie (Filament) on 03/27  at  05:52 PM

The script doesn’t work on IE7 with jquery 1.2.3. The following error is displayed:
Invalid argument.
jquery-1.2.3.min.js
Code:0
Line:24
Char:1337

Comment by Panagiotis on 03/30  at  10:56 AM

Any chance of adding a function to equalize the baselines of divs inside the container? Similar to this:

http://v3.thewatchmakerproject.com/journal/354/equalising-box-baselines-with-javascript

So you can go from this - http://jsbin.com/eguze - to this - http://jsbin.com/ofehi

Comment by Sam on 04/02  at  10:04 PM

Great plugin!
It’s beautifully crafted, I was wondering though is there a way to incorporate callback function for when all the images have completed loading? Im sorry Im a terrible code reader ...

Comment by benson on 04/13  at  05:28 AM

I’ve used similar plugin long ago

http://www.tomdeater.com/jquery/equalize_columns/

it gives the same result.

Comment by Mahbub on 04/15  at  12:52 PM

Good technique. I solved the height problem in firefox on Linux machine by this technique for my layout. It’s working fine for me. Thank You

Comment by aloy on 05/18  at  03:46 PM

Very useful..But i am still not clear about not using CSS ...

Comment by Richard on 05/21  at  01:07 PM

Wow, this is awesome!

Comment by ArthasMX on 05/23  at  02:02 AM

Hi, great script!

I also had the issue with line 24, and commenting it out worked fine. Only reason I mention is because the page states that it should default to px if the pxToEm script isn’t present, but it doesn’t work unless you comment this out.

Also, what is the symantically correct way to clear your floated divs here without having your clear div also set to the min-height?

Thanks!

Comment by Justin on 05/27  at  05:42 PM

Great script. I had hacked up my own version, but yours does the job more elegantly than mine did.

One item of note: when writing a jQuery plugin, you should use jQuery in place of the $ shortcut, as people might be using jQuery in no-conflict mode, thereby breaking your plugin.

Comment by Matt Wiebe on 05/27  at  06:11 PM

Had to rip apart a client supplied table based design today with a VERY short deadline - remembered your script and worked great!

The pxtoEm part stalled javascript so I removed as I didn’t need it.

Had one issue not mentioned before - I had a div with images in floated to the right of it’s sibling - as the text was far taller than the floated div, the non float wrapped under, so when the equalHeights script was called it sized the float div correctly to the height of the sibling, HOWEVER after the resize, logically the sibling increased in height due to no longer wrapping under the float - this resulted in mismatched heights again.

Made a very small change to the script to recursively call until a match was 100% certain:

$.fn.equalHeights = function(px,matched) {
$(this).each(function(){
var currentTallest = 0;
$(this).children().each(function(i){
if ($(this).height() > currentTallest) { currentTallest = $(this).height(); }
});
if ($.browser.msie && $.browser.version == 6.0) { $(this).children().css({’height’: currentTallest}); }
$(this).children().css({’min-height’: currentTallest});
$(this).children().each(function(i){
if ($(this).height() > currentTallest) matched=false;
else matched=true;
});
if (matched!=true) $(this).equalHeights(true,false);
else return this;
});
};

it’s called with a further ‘match’ parameter, initially set to false, ie//

$(function(){ $(’#container’).equalHeights(true,false); });

Comment by Dan Woodroffe on 06/01  at  11:19 PM

hi there,
thanks for such a useful script. it works perfectly with my firefox browser but for some reason its not working with IE7. i am using 3 column div lay out…
thanks
-jubair

Comment by jubair on 06/02  at  11:03 PM

RE: Nate on 02/09

Adding height and width attributes to your image tags will help browsers render the page quicker as well as prevent content shifts as the page loads. May help with your equal columns, too.

Comment by benxamin on 06/04  at  03:37 PM

This is explained lucidly and it worth giving a try. And thanks for sharing the same!

Comment by Bell on 06/05  at  07:56 AM

So this doesn’t seem to work for me.  When I inspect in Firebug the two container heights are being set equally (which is good).  However when I show/hide content within one of the containers, the min-height does not change for either container and thus results in unequal heights.

HTML

<div id="promoGiftSection">
<div id="promoCodeSection">
Sorry!  This promotion requires a membership
<input name="promoCode" type="text" id="promoCode" />
<input name="go" type="button" />
</div>
<div id="giftCardSection">
<h4 class="baseCopyEm">Gift Card or eCertificate</h4>
<input name="giftCard" type="checkbox" id="gcFieldsToggle" />
<label for="gcFieldsToggle" class="inline">I have a Gift card</label>
<ul id="gcFields">
<li>
<label for="giftCardNo">* Card Number</label>
<input name="giftCardNo" type="text" id="giftCardNo" />
</li>
<li>
<label for="giftCardPIN">* PIN</label>
<input name="giftCardPIN" type="text" id="giftCardPIN" />
</li>
<li class="submit">
<input name="go" type="button" />
</li>
</ul>
</div>
</div>

JS

$("#promoGiftSection").equalHeights(true);

Comment by Dylan MacDonald on 06/11  at  01:28 AM

A question to the filament group:
Is there any way to combine this script with CurvyCorners ( http://www.curvycorners.net/ )? I cant get it to work :(

Comment by Samuel Milton on 06/11  at  12:38 PM

Nate, that’s a clever hack for handling columns withs images. thanks…

Comment by maheswaran krishnan on 06/22  at  03:22 AM

do you want the really shortcut ? use class :D

<div id=’div1’ class=’sameClass’></div>
<div id=’div1’ class=’sameClass’></div>
<div id=’div1’ class=’sameClass’></div>
<div id=’div1’ class=’sameClass’></div>
<div id=’div1’ class=’sameClass’></div>
<div id=’div1’ class=’sameClass’></div>

.sameClass{
height: 300px;
}

done !!!

Comment by adwin on 06/29  at  04:04 AM

Thanks for sharing, looked long back today got a chance to use this! works exactly as required!! thanks again!! :)

Comment by Vipul Limbachiya on 07/07  at  02:22 PM

Nice tutorial!
I´ve been using CSS in my projetcs and this script above will be extremelly useful.
Thanks a lot!

Comment by arquivo deslizante on 07/13  at  02:17 AM

I used CSS solution to get equal heights for solid layouts in my drupal themes, preferred matthew’s holy grail technique rather than alisapart. Yet this sort of javascript’s solution may also come in handy with simple page elements or blocks, especially when I have to dynamically generate blocks, and the blocks have to be flexible enough that may exist whether they are one, two, three, .. etc column blocks in various pages. Thanks for the tut.

Comment by gaus surahman on 07/14  at  09:34 AM

Any idea why I would have to refresh the page for the change to take place?

When the page originally loads I see the unequal columns.  But, once I hit refresh the columns equalize.

I am using FF3 on a mac.

Comment by Benjamin on 08/06  at  05:37 AM

Very Nice, Thank you for your sharing .

Cheers
Elijah

Comment by Dindigul on 08/25  at  01:01 PM

displaying “G.replace not a function” error. 
i got prototype.js and jquery-1.3.2.min.js in same page.
i did replace $ with jQuery and include jQuery.noConflict().
but still showing above error.

Thanks.
rvs

Comment by rvs on 09/23  at  06:45 PM

提供下载吗?

Comment by lgh on 09/25  at  05:36 AM

The information provided is very useful to harness our skills further. This really provides a good understanding and simple explanation of the material.

Comment by Payday money on 10/05  at  12:22 PM

biligiler cok iyi ya beendıms aolun

Comment by sikiş izle on 10/26  at  10:31 PM

tanks for the information, its much usefull.  i will comment in my blog about your post.

tank you.

Comment by boutique arte angels on 11/14  at  12:08 PM

vety nice taks admin

Comment by sikiş on 11/18  at  05:19 PM

i use the same method but i fnd some throble with ie8 some body know any solution? (my tables don’t show).

Comment by criacao-sites on 11/22  at  09:29 PM

I like this solution, it can save some annoying div nesting, but i use css instead(thanks to Mathew James Taylor for that), because you’ll usually have dinamyc content and when objects move around the heights change. With css all columns preserve the same height.

Comment by Amos on 11/26  at  12:36 AM

hi, this solution that all i search some many time, tank you for your publication.

Comment by travel airfare hotel on 11/28  at  12:02 PM

Hi guys,

I have a little problem with this plugin.

In my div #equalize, I have another div with class minifiche and another one with css clear: both. EqualHeight works perfectly with minifiche but it give the same height to the div with clear.

How can i resolve this ? Thx.

Comment by Kcin on 12/02  at  03:05 PM

After many try, I manage to do what I want.

$(’#clearer’).css({’height’: 0 + ‘px’});
$(’#clearer’).css({’min-height’: 0 + ‘px’});

Very simple :D

Comment by Kcin on 12/02  at  03:58 PM

Great plugin! It works fine in Firefox and IE, but in Chrome it’s not working at all here

Comment by Jorre on 12/31  at  02:58 PM

Hi this is nice code, but when I add any paragraph in B box then on IE 6 or IE7, I will get 2 px more height. Compare A and C boxes. Please give me any solution.

Thanks

Amol Kshirsagar

Comment by Amol on 01/02  at  07:59 AM

Nice solution man, its so easy to do it when we use table
Thx for the script, ill definitely try it on my new project

Cheers

Comment by Rudi on 02/19  at  09:26 AM

Nice solution man, its so easy to do it when we use table
Thx for the script, ill definitely try it on my new project

Comment by Sikis Hikayesi on 03/07  at  07:46 PM

Hi guys,

I have a little problem with this plugin.

In my div #equalize, I have another div with class minifiche and another one with css clear: both. EqualHeight works perfectly with minifiche but it give the same height to the div with clear.

How can i resolve this ? Thx.

Comment by Sikis Hikayeleri on 03/07  at  07:47 PM

great text thanks admin.

Comment by sikis izle on 03/09  at  02:21 AM

This promising script drove me bonkers until I read the comments about commenting out line 24, then it worked! Thanks. I would love to see this simple fix included in the intro of the script itself.

Comment by Frances Cherman on 03/09  at  03:12 AM

not same view with print result

Comment by fathul wahhab on 03/24  at  10:50 AM

hi I have got problem, This isnt work when cols is not in same container :(

Comment by Kostkac on 03/28  at  04:21 PM

@Kostkac: yes, that’s a restriction due to how these functions are currently set up, but it wouldn’t be difficult to extend them with an option to equalize the heights of several unrelated elements. Patches are welcome! :)

Comment by Scott (Filament) on 03/30  at  04:45 PM

Fantastic! Just what I was looking for. Fingers crossed that it’s going to work well with my sortable list :)

Comment by Ben on 04/01  at  02:17 AM

You fucking beauty!!!

Comment by Darren on 04/14  at  05:54 PM

Why not use tables? In this case it may be more elegant...?

Comment by Scott Kellum on 04/16  at  04:08 PM

Very nice javascript solution for this well known “problem”.  And it’s easy to implement. Thx for sharing!

Comment by CSS-Design on 04/27  at  05:18 PM

I am not able to make this working - trying to make it work on http://fuva.eu
I put this:

baseurl ?>/templates/<?php echo $this->template?>/js/jQuery.equalHeights.js">


$(’.columns’).equalHeights();

into the head of html and attached class columns to desired colums and copied the script to correct place with name jQuery.equalHeights.js

Could you please tell me what Im doing wrong? Thanks

Comment by Vasik on 05/21  at  11:14 PM

hey filament team,

first: very cool solution, exactly what i searched for. :) but i have one problem, it doesn’t work in the safari-browser (win & mac). is there a solution for this? thanks.

Comment by manuva on 06/11  at  07:08 PM

thank you admin cik

Comment by sikiş on 06/29  at  12:18 AM

There’s a logic error in `if (!px || !Number.prototype.pxToEm)` – that means “if the user did not set the px flag OR pxToEm does NOT exist, call pxToEm”, which causes a runtime error if pxToEm is not loaded, disregarding the px flag.

A more useful logic is `if (!px && Number.prototype.pxToEm)`, making the px flag decide what to use, and only call pxToEm if it exists.

Comment by Mikkel Høgh on 07/03  at  12:42 PM

For those of us newbies.... you need to paste this script in your <head> section somewhere after the script

$(function(){ $(’#parentelement’).equalHeights(); });

The #parentelement id in this case is the parent element.

You’ll also need to link to jquery. Here’s a hotlink you can use. This also goes in your <head> section.

Comment by Briton on 10/06  at  05:05 AM


$(function(){ $(’#contentarea’).equalHeights(); });

Comment by Briton on 10/06  at  05:06 AM

oh forget it. It keeps stripping my tags

Comment by Briton on 10/06  at  05:06 AM

I had to remove the conditional comparison on line 24, because of error “currentTallest.pxToEm is not a function”. I believe I followed all instructions to include the toEm() and toPx() jquery plugins, and loaded pxem.JQuery.js before it’s called by equalHeights.js.

`if (!px || !Number.prototype.pxToEm) currentTallest = currentTallest.pxToEm();`

I also tried this, which produced the same error:

`if (!px || !Number.prototype.toEm) currentTallest = currentTallest.toEm();`

Comment by Opally on 11/11  at  07:26 PM

Thank. Very usefull

Comment by webunique on 12/13  at  05:22 PM

thanks adminzzz a ssiktir lann .

Comment by sikiş on 12/13  at  09:56 PM

great work! I like it very much, wish you can possess a glance at my site.

Comment by Moncler on 01/04  at  05:31 AM

thanx admin by points gol

Comment by escort on 01/20  at  12:30 PM

Does anyone know why it adds an extra space at the bottom? It calculates the height but it gives me a higher height than the highest element.

Help?

Comment by CIPPO on 01/22  at  03:27 PM

This site is very great and indispensable to my thank you to expect continued success with the authorities there are millions of people come easy memlunkalan but I guess I did not bring the language

Comment by eren on 01/31  at  11:21 PM

This site is very beautiful and I had a really great site I would suggest you check in and thank this site has what i call

Comment by porno on 02/02  at  10:59 PM

HI am from madurai… this is really super…

Comment by srini on 02/07  at  04:05 PM

This site is very beautiful and I had a really great site I would suggest you check in and thank this site. good admins

Comment by hosting on 02/08  at  08:28 PM

Thanks admin.Very

Comment by epoksi on 02/19  at  03:27 AM

Very Me See.Good

Comment by gelinlik on 02/19  at  03:28 AM

Me Good Yes.Feed

Comment by gelinlik modelleri on 02/19  at  03:28 AM

See Muching Good.

Comment by gelinlik fiyatları on 02/19  at  03:29 AM

Very Me Soory.

Comment by tesettür gelinlik on 02/19  at  03:34 AM

Thank you for the article. Can I share that article on my website? If you allow, please contact with me via my email address.

Comment by hostgator on 03/03  at  10:19 PM

Actually found this to be more efficient :)


/**
* jQuery Plugin Function
*
* Make all elements same height according to “tallest” one found :)
* Original code : http://codesnipp.it/code/441
*/
jQuery.fn.equalHeights = function() {
return this.height(Math.max.apply(null,
this.map(function() {
return jQuery(this).height()
}).get()
));
};

Your welcome ;)

Comment by John Clarke on 03/08  at  11:09 PM

thank mank yonk vru silipilii

Comment by sikiş on 04/06  at  02:22 AM

The plugin is not compatible when used with other javascript frameworks. For e.g. Prototype. Please use
(function($){
.....................................
.....................................
.....................................
})(jQuery);

inside your plugin file. i.e. jQuery.equalHeights.js in order to use it with the : jQuery.noConflict();

Comment by Binod Kumar Luitel on 04/08  at  12:06 PM

Is there any way of getting this to exclude elements from the resizing? I’m using it to match the height of DIVs but would really love if it could be set to exclude contained paragraph elements!

Many thanks for this brilliant tool!

Comment by mm on 04/25  at  06:19 PM

Hello Filament Group,

I have been using your equal heights plugin in my various projects but today while I was using it @ one of my Magento’s project I stumble upon a problem. The equal height plugin is not getting applied to the not visible element. I even use the :hidden selector but of no use. Can you please guide me what is the problem.

Thanx

Comment by Binod Kumar Luitel on 04/28  at  12:23 PM

Commenting is closed for this post.

Book cover: Designing with Progressive Enhancement

Enjoy our blog? You'll love our book.

For info and ordering: Visit the book site