One aspect of HTML and CSS I’ve always felt is lacking is the ability to distribute elements evenly within its container. Using the CSS rule text-align:'justify', you are able to justify lines of text within their container, but there’s really no equivalent for non-text elements.
This became a problem a few weeks ago when a client requested that their site menu span the entire width of the page. Before discovering CSS, I would accomplish this using tables and images. But since then, I’ve learned that images are quite inaccessible and can be very difficult to maintain when the menu changes, and since this site was being built using CSS, I wanted to keep tables out of the design as much as possible. So, for the time being, I created something like the following.
1 2 3 4 5 6 7 8 9 10 11 | <html> <body> <ul id="container"> <li>Home</li> <li>About Us</li> <li>Services</li> <li>Resources</li> <li>Contact Us</li> </ul> </body> </html> |

That was all well and good, but it wasn’t going to fly with the client.
After digging through CSS documentation and finding little that addresses this problem, I decided the best way to accomplish this effect was to use javascript to dynamically generate CSS. I’m hoping a feature is added to CSS soon since I’m not a big fan of using javascript for design.
While scripting this method, I made a list of characteristics I’d like to see it have.
- Utility
- Scalability
- Simplicity
With those goals in mind, I came up with this frame for the method.
distribute(container, elements, [direction = 'horizontal', className = null])
Container (required)
The id attribute or HTML object of the container.
Elements (required)
The tag name of the element(s) you want to distribute within container (e.g. ‘li’, ‘img’, ‘div’).
Direction (optional)
The direction you wish to distribute elements. This can either be ‘horizontal’ (default) or ‘vertical’.
ClassName (optional)
If you have multiple instances of elements and only want to distribute certain elements, you may attach a class to those tags and pass that to the method. This property is null by default.
Let’s take a look at the script (the following script was written with Prototype).
1 2 3 4 5 6 7 8 9 10 11 12 13 | var containerDimen = Element.getDimensions(container); var element = $A($(container).getElementsByTagName(elements)); if (direction == 'vertical') { var containerHeight = containerDimen.height; containerHeight -= (parseInt(Element.getStyle(container, 'padding-top')) + parseInt(Element.getStyle(container, 'padding-bottom'))); } else { var containerWidth = containerDimen.width; containerWidth -= (parseInt(Element.getStyle(container, 'padding-left')) + parseInt(Element.getStyle(container, 'padding-right'))); |
The first thing we need to do is collect all elements within the container. We’re using the $A() method to make the results Enumberable so we can run them through an each() loop a little later. After we’ve gathered all the elements, we need to calculate the container width or height (depending whether direction is set for ‘horizontal’ or ‘vertical’). Since the box model calculates width as the sum of width and padding, we have to subtract the padding from the width to get the real width of the container.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var elementWidth = 0; var elementHeight = 0; var i = 0; element.each(function (e) { if ((className == null) || ((className != null) && (Element.hasClassName(e, className)))) { i++; var elemDimen = Element.getDimensions(e); if (direction == 'vertical') { elementHeight += elemDimen.height; Element.setStyle(e, { marginTop: 0, marginBottom: 0 }); } else { elementWidth += elemDimen.width; Element.setStyle(e, { marginLeft: 0, marginRight: 0 }); } } }); |
Now that we have the container width (or height), we need to calculate the total width (elementWidth) of all the elements. If there were any margins applied to the elements for a noscript version, we remove them. i is used to count how many elements match the search criteria since className may or may not be null.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | if (direction == 'vertical') var leftover = containerHeight - elementHeight; else var leftover = containerWidth - elementWidth; var marginNum = i - 1; var margin = Math.floor(leftover / marginNum); element.each(function (e) { if ((className == null) || ((className != null) && (Element.hasClassName(e, className)))) { if (direction == 'vertical') { if (e != element[element.length - 1]) Element.setStyle(e, { marginBottom: margin + 'px' }); } else { if (e != element[element.length - 1]) Element.setStyle(e, { marginRight: margin + 'px' }); } } }); |
We’re just about done! With the elements and container width calculated, we figure out how much space is leftover. The leftover space is divided by i minus one (we’ll only be applying margins to the right side of elements) to figure out how much space should be between each element. All that’s left to do after that is to place those margins on each of the elements.
With the javascript written, all that’s left to do is make a little modification to the HTML.
1 2 3 4 5 6 7 8 9 10 11 | <html>
<body onload="distribute('container', 'li')">
<ul id="container">
<li>Home</li>
<li>About Us</li>
<li>Services</li>
<li>Resources</li>
<li>Contact Us</li>
</ul>
</body>
</html> |

That’s it. It’s probably a good idea to add default margins to the elements for users with javascript disabled (any default margins get removed by the script). Enjoy!
Resources
The script in this post uses Sam Stephenson’s Prototype library. There’s some very good documentation for Prototype written by Sergio Pereira and over at script.aculo.us (another great javascript library).
Download the Source
All source code is provided under the Creative Commons Attribution-Sharealike License. If you agree to these terms, please view and download the entire source now.


October 7, 2006
Oh my dear Garrett,

use an unordered list or two for this problem, and you have no *div* soup or anything else to code.
pure css is always better.
have a nice day and read http://www.cssplay.co.uk/index.html Stu is a one of the best in css for me.
Monika
October 11, 2006
Hi Monika: There’s no solution to this problem on the site you provided.
From what I’ve seen, there’s no way to tell CSS to distribute elements within their containers. That’s why I wrote the javascript.
If anyone has a pure CSS solution, please share it. I’d much rather not have to use javascript for these kind of things.
February 13, 2008
Thanks for posting your tutorial — it seems like it should be such an easy thing that a lot of people are doing, but yours is the only answer that google can find for me!
I still can’t get it to work, though. I’ve copy and pasted the html and linked to the js file, but that doesnt fix the problem. Is there some CSS component that I am missing, or another js file that it is dependent upon?
February 12, 2009
Thanks man, worked like a charm. Much better than my own solution I brewed up a year or so ago.
February 13, 2009
I have some issues with this.
Total js payload is around 130 KB, seems overkill for a small tweak. Not good for dialup visitors.
On FF 3.0.5 I ran into out of memory errors. I didn’t check on IE.
Also, Garrett, you might explain to newbies that they need to include two lines in their page header:
Has anyone else checked this on Firefox?
March 30, 2009
Чот не так себе, пойду ещё что нить зачту
May 28, 2010
ashley rossibell mateo pics
baileys kaluha jameson cocktail
ambassadeur parts list
1993 ford mustang cobra serpentine belt diagram
308 balistic chart
cc per gallon
308 balistic chart
455 olds firing order diagram
alpo alberto martinez
1950 vintage bob hair cut
airbus industrie a330 200 seating chart
analysis hughes langston theme for english b
aa12 for sale private buyer
bad luck schleprock
a worn path analysis
100 ml alochol equals how many ounces
6 5 x 284 load data
ammonia discharge smell during pregnancy
sears kenmore agitator series 70 remove
1917 enfield receiver cracks
June 12, 2010
anne margaret 2010 svu
14 feet 10 inches equals cm
bangal hot porntube
1 8 quarts to cups
200 milligrams equals
abby winters pregnant model rosanna
8mm mauser ballistics
9mm silencers
nicki minaj plastic surgery
5 grams equals milligrams
actores argentinos cojiendo
amoozeshe amizesh
106 7 radio the fox denver
917 marlin stocks
auto glass repair philadelphia
12 jahre old girls
91 caprice lift kit
107 hoova crip
albino mole king snake
486 24442 manual
June 12, 2010
1993 ford 5 8 heater hose diagram
4 3 vortec parts diagram
30 mg converti in ml
bhai baap bahan ki kahani
adelitas bar
22 lr ammo trajectory chart
1987 chevy 454 ecm
7 62 x 54r ammo for sale
89 tracker ecm diagram
african briads maryland
1000 microliters equals how many milliliters
1987chevy silverodo spark plug diagram
07 ford camper shell
att mcfee antivirus
ashanti pussy picture
arreglos florales de quinseañera
csa kuwait com
1981 280zx specs
1894 winchester model 94 3030 rifle
10 kg equals how many pounds
June 30, 2010
20 tsp equals how many cups
argyle stencil for painting
amor duranguenze
amtrak voucher sale
1024chan jb pass
actual ruler sizes on
arreglos para piñatas
10mm vs 40 caliber
alcoholdrink recipes
9mm jennings handgun price
1961 62 police cars
40 mg equals how many teaspoons
50 cal pistol
african pixie braids
at t hronestop elink
12 year old teen sex
antique shotguns parts
ares free music download
abecedario gotico
22 cal german revolver