Align List Items Horizontally with CSS …
… or: “Cross Browser display:inline-block”.
If you ever wanted to display a list of items horizontally with a wrap around once the right margin of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can get… Here’s an example:

Well, yeah… not exactly what you wanted, I guess… It would be nice to have something similar to this:

Usually at this point you stop bothering and use a table, right?
But what about liquid layouts? It would be nice to have “something” that can do the trick with a simple unordered list (ul).
Actually, CSS has a solution for this problem: setting the item to display:inline-block will do. There’s just one minor problem. inline-block is currently only supported by Safari and Opera in a usable way. There are workarounds for Internet Explorer and Firefox. The one for Firefox is extremely buggy, especially when it comes to manually setting the width of an item or when wrapped text should be supported.
I combined the workarounds and found a way to deal with fixed widths of items which results in a cross browser solution for the problem. Check out the demo.
Lets have a deeper look into the six tests of the demo page. All tests are using the exact same markup for the lists - no quirks here ;-).
Test 1: Floated
Just a demo of what we do not want…
Test 2: Standards compliant
With display:inline-block elements get a layout as if they were display:inline, but at the same time they can contain display:block elements. Here are the CSS rules:
#test2 li { display:inline-block; width:60px; vertical-align:top;
overflow:hidden; }
When setting the “li” elements of our list to this display type, we exactly get the effect we want:

Safari and Opera are fine with that - Internet Explorer and Firefox are not… They still display our items as regular block elements.
Test 3: Internet Explorer 6 and 7
Bruno (Fassino?) presents a way to force Internet Explorer 6 to display an element as inline-block. After it has been set to display:inline-block, you overwrite the rule with a second rule to display:inline - and it will do. Yeah I know that’s sounds strange, but it works. I’m using two different CSS filters to also support IE 7:
#test3 li { display:inline-block; width:60px; vertical-align:top;
overflow:hidden; word-wrap:break-word; }
* html #test3 li { display:inline; } /* for IE 6 */
* + html #test3 li { display:inline; } /* for IE 7 */
Test 4: Firefox?
Firefox. Hmhm. Firefox… Well, Firefox doesn’t know inline-block at all. Nicholas C. Zakas describes the problem and suggests to use -moz-inline-stack instead. Right. -moz-xxx stuff. We have to dive deep into the Firefox/XUL internals to find a solution. Stacked elements however are not what we want - we want block elements inside our inline-block. Hence most of the time -moz-inline-box is suggested. The default alignment for elements of a -moz-inline-box however is horizontally. -moz-box-align:vertical helps us here:
#test4 li { display:-moz-inline-box; display:inline-block;
width:60px; vertical-align:top; overflow:hidden; }
But wait - when setting the width of the items (with overflow:hidden), the layout completely collapses:

Apparently -moz-inline-box doesn’t like to have a fixed width and a hidden overflow…
Test 5: Firefox!
So we set the width to the child elements of the list items. This means that only block level elements are allowed to be children of a list item. Not that much of a restriction…
#test5 li { display:-moz-inline-box; -moz-box-orient:vertical;
display:inline-block; vertical-align:top; }
#test5 li > * { display:table; table-layout:fixed; width:60px; overflow:hidden; }
Yeeha - that does the trick!
Test 6: Combining the magic
Loads of browser specific stuff. Here’s how I combined the rules in order to make the layout work cross browser, i.e. in Internet Explorer, Firefox, Safari and Opera:
#test6 li { display:-moz-inline-box; -moz-box-orient:vertical;
display:inline-block; vertical-align:top; word-wrap:break-word; }
* html #test6 li { display:inline; }
* + html #test6 li { display:inline; }
* html #test6 li { width:60px; }
#test6 li > * { display:table; table-layout:fixed; width:60px; overflow:hidden; }
Enough chit chat! How do I use it?
Woa - you read up to here! Here’s a simple way to use the solution. Hack together some markup similar to this:
<ul class="ib-fix demo-ul"><!-- --><li><p>Resize your browser window ...</p></li><!-- --><li><p>... to see what happens with the elements ...</p></li><!-- --><li><p>... in this list.</p></li><!-- --></ul>
The HTML comments are required in order not to have any white spaces inside the “critical section” - we are dealing with inline elements here… See also the limitations section.
Now, add the following ib-fix (”inline-block-fix”) class rules to your style sheet:
.ib-fix li { display:-moz-inline-box; -moz-box-orient:vertical;
display:inline-block; vertical-align:top; word-wrap:break-word; }
* html .ib-fix li { display:inline; }
* + html .ib-fix li { display:inline; }
.ib-fix li > * { display:table; table-layout:fixed; overflow:hidden; }
And set the width of your items via something similar to this:
* html .demo-ul li { width:80px; } /* for IE 6 */
.demo-ul li > * { width:80px; } /* for all other browser */
That’s it - happy aligning.
Limitations
- Always keep in mind that you are dealing with inline elements. As opposed to block level elements, spaces between inline elements are displayed.
- The children of a ib-fix layouted element have to be block level elements, i.e. must not be text children.
- When modifying the DOM via JavaScript, use a single wrapper DIV as the child of your item - otherwise Firefox will insert strange new lines…
Hi, the name's Steffen and I'm writing about the Web, programming
and all those things coming to my mind. Enjoy your stay.
May 6th, 2007 at 20:49
Hehe. So basically, you’re saying that tables are not _that_ bad, after all?..
J/k. Great work.
May 7th, 2007 at 5:20
Thanks for this post!, Its great to have all the tests/rules which need to be taken into consideration in one place.
I’ve been using inline-block in a dev project for a while now(I use Opera), I knew that there was a way to get other browsers to mimick it, but hadnt had the time to search around for a solution which would work 100% cross-browser.
May 8th, 2007 at 2:53
[...] of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can [...]
May 8th, 2007 at 12:55
[...] … or: “Cross Browser display:inline-block”. Spread the word! [...]
May 8th, 2007 at 21:00
Great solution, and thanks! I’ve made a couple changes that i thought i’d share. Here’s my final styling, with just the salient parts (that is, i’ve removed the widths and borders and etc. to showcase the cross-browser functionality ONLY):
.demo-ul li {
display:inline-block !important; // for Safari, Opera, and IE 7
display:-moz-inline-box !important; // for Mozilla
-moz-box-orient:vertical;
zoom: 1; display: inline; // for IE 6
vertical-align:top;
}
This way you don’t NEED the * html and * + html lines at *all*. It takes advantage of the fact that IE 7 adheres to the standard and IE6 has a parser bug with !important rules, as follows:
1. All browsers go through and apply inline-block. (Note that it’s marked !important .)
2. Mozilla then applies -moz-inline-box instead, because it’s marked !important and comes AFTER the other !important declaration. Everyone else ignores it. Mozilla also applies the other -moz declaration.
3. IE6 has a parser bug: the last rule in a given block is applied, REGARDLESS OF MARKED IMPORTANCE. So instead of applying inline-block, it applies inline instead. We add zoom: 1 because it’s a convenient way to apply hasLayout (it will stop your stylesheets from validating, though — be warned. If that bothers you, i recommend replacing it with the following TWO declarations: float: none !important; float: left; which will work the same way.)
Just like to make things shorter and sweeter. Not that my way’s “better”, necessarily, but wanted to show the different approach!
–Adrienne
May 8th, 2007 at 21:01
PS - tested: IE6, IE7, FF2, Opera8. (Which is all the browsers i’ve got here at work.)
June 24th, 2007 at 1:33
[...] of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can [...]
July 9th, 2007 at 14:03
[...] Align List Items Horizontally with CSS Eine plattformübergreifende Methode zur horizontalen Ausrichtung von div-Blöcken mit CSS. [...]
July 9th, 2007 at 14:03
[...] Align List Items Horizontally with CSS If you ever wanted to display a list of items horizontally with a wrap around once the right margin of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can get. This article delivers an easy solution of this problem. [...]
July 9th, 2007 at 15:22
[...] Align List Items Horizontally with CSS If you ever wanted to display a list of items horizontally with a wrap around once the right margin of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can get. This article delivers an easy solution of this problem. [...]
July 9th, 2007 at 17:31
[...] Align List Items Horizontally with CSS If you ever wanted to display a list of items horizontally with a wrap around once the right margin of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can get. This article delivers an easy solution of this problem. [...]
July 12th, 2007 at 5:42
[...] Align List Items Horizontally with CSS If you ever wanted to display a list of items horizontally with a wrap around once the right margin of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can get. This article delivers an easy solution of this problem. [...]
July 25th, 2007 at 13:22
[...] display: inline-block cross browser A nifty way of aligning list items horizontally (tags: css inline list align) [...]
July 27th, 2007 at 14:16
[...] Align List Items Horizontally with CSS If you ever wanted to display a list of items horizontally with a wrap around once the right margin of your page has been reached, you came across a float:left solution. And if you ever tried to line up items with different heights this way, you know how messy things can get. This article delivers an easy solution of this problem. [...]
August 14th, 2007 at 11:12
Your solution is too complex, look at this:
span{display:-moz-inline-box;display:inline-block;vertical-align:middle;overflow:visible;cursor:default;}
aSame appearance in ie and firefox
ie and firefox
ie and firefox
August 21st, 2007 at 11:12
I just had a look at your solution and at diyism’s, and I couldn’t control the width of things as well as overflowing content in his version, even when applied to child containers.
Other than that I’m really torn about using your solution. On one hand it does work for me (with more complex content, I have a div-wrapped image, an h3 and a p in the li), on the other hand I feel it lacks stability. I tested it in a more recent nightly build of Webkit and it worked, but will it work in Firefox 3?
I’m also not fond of the comments to prevent whitespace, but figured that all browsers I tested do display the whitespace in equal width, well, all except IE. As I have a tiny IE-only css anyway (using conditional comments), this does not pose a problem, and it loosens the restrictions a little. Finally, thanks for sharing your solution, it did help me a lot.
August 22nd, 2007 at 7:04
In fact, i’m always looking for an inline-block layout solution.
Although “inline-block” is supported is firfox 3 beta,
but with most people using firefox 2,
what i can only do is to coin an alternative method.
First, this:
span{display:-moz-inline-box;display:inline-block;vertical-align:middle;overflow:visible;cursor:default;}
Recently, this:
span{float:left;vertical-align:middle;overflow:hidden;cursor:default;}br{clear:left;}
August 22nd, 2007 at 7:38
A javascript fixing with the second solution:
August 22nd, 2007 at 7:39
if(window.addEventListener)
{window.addEventListener(’load’, ib_fix, false);
}
else
{window.attachEvent(’onload’, ib_fix);
}
August 22nd, 2007 at 7:40
function htmlspecialchars(str)
{return str.replace(//g, “>”);
}
function trim(str)
{return str.replace(/(^[\r\n\t ]*|[\r\n\t ]*$)/g, ”);
}
August 22nd, 2007 at 7:41
function ib_fix()
{var all_span=document.getElementsByTagName(’span’);
for (var j=0;j
August 22nd, 2007 at 7:42
function ib_fix()
{var all_span=document.getElementsByTagName(’span’);
for (var j=0;j<all_span.length;++j)
{if (all_span[j].parentNode.tagName!=’SPAN’ && all_span[j].getElementsByTagName(’span’).length==0
&& all_span[j].style.cssFloat!=’left’ && all_span[j].style.styleFloat!=’left’
)
{typeof(all_span[j].style.cssFloat)!=’undefined’ ? (all_span[j].style.cssFloat=’none’):(all_span[j].style.styleFloat=’none’);
}
August 22nd, 2007 at 7:44
if (all_span[j].getElementsByTagName(’span’).length>0
&& all_span[j].childNodes.length-all_span[j].getElementsByTagName(’span’).length>0
)
{var a=all_span[j].childNodes;
for (var i=0;i<a.length;++i)
{if (a[i].nodeName==’#text’ && trim(a[i].nodeValue)!=”)
August 22nd, 2007 at 8:18
{var b = document.createElement("span");
b.innerHTML = htmlspecialchars(a[i].nodeValue);
a[i].parentNode.replaceChild(b, a[i]);
}
}
}
}
}
August 22nd, 2007 at 8:20
For example:
<span style="width:700px;border:blue 1px solid;" id="jack">
<span>lkjkdjsf<div>jack</div></span>
<span style="width:200px;height:18px;border:red 1px solid;" id="ppp">aSame appearance in ie and firefox</span>
bbbbb
<span style="width:200px;height:28px;border:red 1px solid;">ie and firefox</span>cccc<br>
<span style="width:150px;height:18px;border:red 1px solid;">ie and firefox</span>
</span>
September 10th, 2007 at 0:16
you’ve saved my day with this hack - thanks.
October 19th, 2007 at 15:46
I had the same problem, but since it was an internal application I just changed to minimum requirements to IE7 and FF3 Minefield.
However I had the same problem with not allowing whitespace. What I did was to shrink the text in the parent and reexpand on the child elements.
#parent { font-size: 1px; letter-spacing: -1px }
.child { font-size: medium; letter-spacing: normal; }
The problem is that IE7 ignores the spaces so the negative letter-spacing doesn’t move anything any closer together in IE7. But in FF3 it shrinks the space down to 1px and since there is a letter the letter spacing does move them closer and eliminate the gap.
The browser specific stylesheet that another commenter used for IE is also a good idea since conditional comments still validate. But this is a pure CSS solution that I feel is extremely clean.
October 25th, 2007 at 13:52
Hello,
I found the display:-moz-inline-box; -moz-box-orient:vertical; seems to make my images expand to the full width of the , so they become stretched. Is there any way around this?
Cheers
January 31st, 2008 at 4:24
This is seriously awesome work. Thank You. Can’t wait until Firefox releases 3.0 with support for display:inline-block.
January 31st, 2008 at 4:25
This is seriously awesome work. Thank You. Can’t wait until Firefox releases 3.0 with support for display:inline-block.
February 9th, 2008 at 1:30
[...] than trying to explain the benefits of this, here’s a real-world example: Align List Items Horizontally with CSS. inline-table behaves in a similar way, only with tables (obviously), making it slightly less [...]
Leave a Reply