Equal height boxes with Javascript

Mar 28 2006

Update 20/04: Steve Clay pointed out that the previous version didn’t work in Opera, so I have updated the code accordingly.

As any convert to DOM scripting will tell you, our temple is built on the twin pillars of unobtrusiveness and graceful degradation; your website’s functionality must not rely on scripting, but rather it should act as an additional layer of behaviour to enhance your users’ interaction experience.

Or custard, of course.

Whichever laboured metaphor you choose, they key is that your site experience should not suffer through the user’s lack of Javascript.

But what of your site’s appearance?

Fixing your layout without CSS hacks

Quite often when designing you’ll require a series of boxes of equal height, usually arranged in a row; but with variable amounts of content, getting CSS to play nicely and give them all the same height can require quite a bit of hackage or advanced CSS properties that a certain popular browser doesn’t grok.

Personally, I don’t think resorting to minor bouts of divitis is worth it when a simple script can deliver the same thing to almost all users – so here’s a little bit of functionality I developed on a couple of recent projects to do just that.

Extensibility

One key requirement was that the script was extensible – I didn’t want to have to be editing it each time I needed to use it – so the function takes a list of element ids as its arguments, checks that they all exist, and expands their heights to match the tallest.

  1. var BoxHeights = {
  2. maxh: 0,
  3. boxes: Array(),
  4. num: 0,
  5. equalise: function() {
  6. this.num = arguments.length;
  7. for (var i=0;i<this.num;i++) if (!$(arguments[i])) return;
  8. this.boxes = arguments;
  9. this.maxheight();
  10. for (var i=0;i<this.num;i++) $(arguments[i]).style.height = this.maxh+"px";
  11. },
  12. maxheight: function() {
  13. var heights = new Array();
  14. for (var i=0;i<this.num;i++) {
  15. if (navigator.userAgent.toLowerCase().indexOf('opera') == -1) {
  16. heights.push($(this.boxes[i]).scrollHeight);
  17. } else {
  18. heights.push($(this.boxes[i]).offsetHeight);
  19. }
  20. }
  21. heights.sort(this.sortNumeric);
  22. this.maxh = heights[this.num-1];
  23. },
  24. sortNumeric: function(f,s) {
  25. return f-s;
  26. }
  27. }
  28. Download this code: /code/boxheights.txt

Then to fix the box heights we call the equalise method, passing it a list of element ids:

  1. window.onload = function() {
  2. BoxHeights.equalise('one','two','three','four');
  3. }
  4.  

Here’s a very simple demonstration.

Improving the effect

You may have noticed in the example above that there is a brief flicker between the page loading and the script running. Luckily, there is a solution – Dean Edwards solved the window.onload problem a few months ago – which means our equal height columns can slot neatly into our layout without any flicker at all.

Users with no Javascript support get boxes of uneven height, but it’s hardly as if that is a usability or accessibility problem; and the underlying HTML and CSS is easier to maintain than if you had used a complicated pure CSS solution.

Filed under: DOM, Javascript.

Digg this article

Bookmark this article with del.icio.us

Previously: Roundup

Next: Stripe your tables the OO way


Comments

Kev
828 days ago
Nice one Matthew. Better than the overblown solution I came up with by miles.
#1
Matthew Pennell
828 days ago
Cheers, Kev – I’ve found though that it doesn’t work in IE5 as that browser doesn’t support the push or sort Array methods; I’m looking for alternatives now.
#2
Alex
826 days ago
by some strange coincidence I came across this today
http://www.paulbellows.com/getsmart/balance_columns/
which you may or may not already be aware of.
#3
Matthew Pennell
826 days ago
I hadn’t seen that before – I think mine is nicer, though. ;)
#4
draco
826 days ago
Nice one, though I’m perfectly comfortable with using additional divs/CS S to handle problems where design is concerned.

Divitis don’t bother me much though I’ve learnt to keep the usage of it low.
#5
alex
807 days ago
i’m don’t understand anything about javascript..:) but Thanks for the article
#6
Steve Clay
805 days ago
Fails in Opera 8 and 9tp2. The heights collapse to about 1em.
#7
Matthew Pennell
805 days ago
Thanks, Steve – I’ve fixed that now. It looks like Opera didn't like the scrollHeight property, so I've changed it to use the offsetHeight instead, which picks up the correct heights.
#8
Simon Douglas
664 days ago

I love this script, much better than the Project VII one I was looking at. However, once I had realised that I couldn’t pass parameters to Simon Willison’s ‘addLoadEvent’ function, my columns are still differing by 20px. Could it be that the padding/margin on one of the elements if confusing the calculations?

#9
Matthew Pennell
664 days ago

Simon: It won’t be the padding, as the calculated height takes that into account. Possibly you have differing top/bottom margins on the columns, in which case you might need this addition to the script

#10