Equal height boxes with Javascript
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.
var BoxHeights = {maxh: 0,boxes: Array(),num: 0,equalise: function() {this.num = arguments.length;for (var i=0;i<this.num;i++) if (!$(arguments[i])) return;this.boxes = arguments;this.maxheight();for (var i=0;i<this.num;i++) $(arguments[i]).style.height = this.maxh+"px";},maxheight: function() {var heights = new Array();for (var i=0;i<this.num;i++) {if (navigator.userAgent.toLowerCase().indexOf('opera') == -1) {heights.push($(this.boxes[i]).scrollHeight);} else {heights.push($(this.boxes[i]).offsetHeight);}}heights.sort(this.sortNumeric);this.maxh = heights[this.num-1];},sortNumeric: function(f,s) {return f-s;}}- Download this code: /code/boxheights.txt
Then to fix the box heights we call the equalise method, passing it a list of element ids:
window.onload = function() {BoxHeights.equalise('one','two','three','four');}
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.
Bookmark this article with del.icio.us
Previously: Roundup
Next: Stripe your tables the OO way
Comments
- Kev
- 1445 days ago
- Nice one Matthew. Better than the overblown solution I came up with by miles.
- #1
- Matthew Pennell
- 1444 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
- Matthew Pennell
- 1442 days ago
- I hadn’t seen that before – I think mine is nicer, though. ;)
- #4
- draco
- 1442 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
- Steve Clay
- 1422 days ago
- Fails in Opera 8 and 9tp2. The heights collapse to about 1em.
- #7
- Matthew Pennell
- 1421 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
- 1281 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
- 1280 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