spreading list items / when ideas fail

css can be deceptively tricky. Even a simple problem can become a serious drag. The following issue has been plaguing me for more than a year now, so I decided to just throw it out in the open and pray for a good solution.

How to spread a list evenly across the total width of a container. The problem is straight-forward enough. Yet I can't get it to work cross-browser. Once in a while, a new idea pops up, but there's always one browser that doesn't want to cooperate.

the setup

The basic html is easy as can be. We start from an unordered list with 4 items. The code:

<ul class="clearfix"> <li class="first">item 1</li> <li>item 2</li> <li>item 3</li> <li class="last">item 4</li> </ul>

Our goal with requirements:

  • The list items are evenly spread across the whole width of the container.
  • There are no gaps showing between the list items.
  • The list is supposed to keep its behavior in a liquid/elastic layout.

(typical reset css statements and browser fixes are not included in the code previews)

idea 1: when 4 times 25% isn't 100%

ul li {width:25%; float:left;}

The most logical solution is to float all list items and give them a width of 25%. Sadly, rounding errors prevent us from using this technique. While Opera and Safari end up with a resulting width below 100%, IE has a resulting width exceeding 100%. As all list elements are floated this means the last element keeps dropping to the next line when the container is resized. So no go.

Another problem is Opera's handling of % sizing. It can't handle fractions (so no 33.33% for Opera, it reverts to 33%). This makes the behavior across browsers rather unpredictable and leaves Opera with a gap that contradicts our requirements. Another option is to tinker with the percentages (33% - 34% - 33%) but again this contradicts our requirements (and still doesn't solve the initial rounding problems).

check out the first test case

fun with floats, margins and paddings

ul {padding-right:75%;} ul li {float:left; width:100%;} ul li+li {margin-right:-100%; float:right;} ul li+li+li {margin-right:-200%;} ul li+li+li+li {margin-right:-300%;}

Second idea I had was to give the ul element a right-padding of 75%. Making all list items 100% wide make them 25% wide compared to the whole container. The first item would be floated to the left. The following ones would be floated to the right. And to finish it off, all items except for the first one would be repositioned to with a negative margin.

This goes well for Firefox, Opera and Safari until a border is applied to the ul element. This screws up the 75% padding calculation which leaves us with another gap. Not good. We could wrap the list and apply the border to the wrapper, which would at least fix that problem.

Sadly, IE totally screws up this method. Negative margins going above 100% are set to a default 100%, making our little trick useless. Furthermore, IE6 can't handle the + operator in css. This would mean that each list item would have to receive a separate class. Too much hassle, certainly when considering the list could be expanded with new items.

check out the second test case

looking at column layouts

ul li {width:25%; float:left;} ul li.last {margin-left:75%; float:none; width:auto;}

A fresh idea. Let's mimic the behavior of column layout tricks. I gave all li elements a width of 25% and floated them to the left. The last li element was reset to normal behavior and was given a margin-left of 75%. This should do the trick alright.

IE7 handles this as should be expected. Opera, Safari and IE6 show a little gap between the third and last item. This could be solved by applying a left margin that is slightly smaller (let's say 74.5%).

Sadly, Firefox blows up on this method, applying to left margin from the third list element, throwing the last element out of the container.

check out the third test case

meh

And that's as far as I got. Help on this one would be really appreciated. I wouldn't mind a solution with an extra wrapper, I would mind having to label all my list items with a separate class. Any improvements on above techniques are welcome.