inline-block vs float/thinking horizontal

published on:
April 07, 2010
comments

With display:inline-block finally ready for everyday use across the most popular browsers (in all honesty, it has been for a while now), I quickly hit a pretty big dilemma. When comparing inline-block to floats, it wasn't immediately clear what the exact differences were and what method to prefer. I looked online but couldn't find a source listing the difference between the two. Guess that's a good reason for keeping a blog then.

Note that inline-block still needs fixes in IE6 and IE7 (more about that later this week) and isn't supported in FireFox versions prior to FF3. There is a -moz fix if you still want to support these browsers though. Apart from those (easy to fix) issues, you can play around with it all you like.

looking alike

At first sight inline-block and float (left) look incredibly alike, and in a fair few situations both statements can be used to accomplish the same visual effect. Both statements are used to create a horizontal flow rather than the standard vertical flow. A popular design element for navigation, image lists, product lists and a whole range of other commonly used web patterns. That's where the confusion started for me, as randomly choosing a method isn't really my kind of thing.

The inline-block value was created to give an element two different faces. Its parent will treat it as an inline element, with all the typical inline properties. But the element itself considers itself a block element, meaning it can have widths, heights, paddings, margins and all other popular properties of block elements.

Finding the differences

As much as they seem to have in common, once you start looking at the finer points it becomes clear that both methods can be used to different effect and both have their own set of use cases. Below is a list of the most visible and useful differences, allowing you to make a weighted decision when confronted with the choice.

1. horizontal positioning

Horizontal positioning is probably the most important difference, or at least the one I needed the most. Parents can position inline-block children using the text-align property. This means you can actually center a block-property container without knowing its horizontal dimensions. A typical example is that of pagination that needs to be centered, no matter how many pages are displayed. This was pretty much impossible if you wanted to apply fancy styling (not just some text links). Another thing you can do is align all children in normal source order to the right of the container, previously impossible for more complex elements (unless you added a couple of extra floats + wrapper).

Floats can't be centered, let alone be controlled by their parent. Left-floated elements do behave pretty much like normal inline-block elements, but right-floated elements will change order. The first element will be at the far right, the second element will hug the left side of the first element, etc etc. This can be useful behavior, but it's not always wanted. A clearer advantage of floats is that you can float children in separate directions without directly influencing any of its peers. In our pagination example, the 'previous' link can be floated to the far left, the 'next' link can be floated to the far right, while leaving the number navigation centered. You can't do that with inline-block elements.

2. to flow or not to flow

Inline-block elements aren't taken out of the flow. This means that you won't need any clearing nonsense on the parent. No clearfix class, no abuse of overflow:hidden or any other ugly trick to make the parent semi-aware of its children. Quite lovely indeed.

Floats are taken out of the document flow. Even though this has caused us a lot of trouble, it is there for a very simple reason, allowing us to float text around an image (the original intent of the float). Related to this is the ability to clear floats. You can force elements to the next visual line, something which can't be done when using inline-block elements. One thing I thought of was using the ::after pseudo-element in combination with a line feed to force the following elements down, but no luck so far. Haven't been able to get anything in the content property that doesn't come out as simple text.

ul li:nth-child(3n)::after {content:"--fake enter--";}

3. the baseline

Inline-block elements are positioned against the baseline of the text. This means you have way more vertical control. Additionally, when an element breaks to the next line it will never "hang" behind any of the previous elements but will always start at the left-most side of its parent. In some cases this will remove the need of a "row wrapper". It's interesting behavior which has some unforeseen advantages, but more about that in one of the following articles.

Floats will always align at the top, but can be made to hang behind a previous float. When a list of floats reaches the right side or the parent, the next element will either hit the left-most side or the right side of a previous float sticking out at the bottom. Once again, this can be useful in some particular cases, so it really depends on the situation what you would be using.

4. white-space

The biggest down-side of inline-block elements is that they take into account html white-space just like other inline elements do. I still haven't found a good way to eliminate this yet through css, of course you can always use the old html trick to do this, but clean it ain't. Floats don't have this problem at all, which could be a strong factor in choosing which method to apply.

conclusion

Seeing all the differences, there are quite a few differences than can help you decide what method to use in a particular case. If you want control over alignment, inline-block is usually the best option, but if you want more control over individual elements then floats are still preferred.

Then there will still be situations where both methods will yield the same result. For now I guess I'll go with the inline-block method, if only to learn more about the ins and outs of this display value. I'm sure there are more differences, be sure to list them if you think I've forgotten something.

Later this week there will be more info about inline-block in IE, after that there will at least be one more article revealing a pretty interesting technique using inline-block. So stay tuned.

Comments

Bobby Jack

comment number
date
April 09, 2010 14:50

Excellent description of the differences - I really need to start experimenting with inline-block more. In particular, your initial explanation ('parents consider it an inline, element considers itself a block') is one of the nicest clarifications of tricky CSS behaviour I've ever come across.

Ideally, I'd love 'float' to revert back to its original usage (as you point out, pretty much wrapping text around an element) as opposed to some of the layout abuse it's suffered from ever since we dropped tables-for-layout. Not sure inline-block is a perfect replacement, though.

No mention of vertical alignment?

Niels Matthijs

comment number
date
April 09, 2010 15:44

Talk about vertical alignment is coming up :)

The main issue with inline-block behavior so far is that it generates white space between elements. Floats are neatly placed next to each other, but inline-block elements where there's html white-space generate an extra space between elements. Still haven't found a way to get around this particular issue.

It's not a bug though, but still pretty annoying when trying to replace floats with inline-blocks.

Chuck Norton

comment number
date
April 12, 2010 01:08

Sweet post. I remember playing w/ inline-block a while back & have completely forgotten about it. No more parent clearing is promising indeed! -Thanks!

Brandon Sheppard

comment number
date
April 12, 2010 01:29

I've always loved inline-block's — they tend to flow much better than floats — they just feel way more natural in a layout. But like everything, there are situations where you just can't use them.

Tim G

comment number
date
April 12, 2010 07:28

Re the white-space issue: it's possible to use negative horizontal margins on your LIs. With text-based list-items, at least, the amount necessary at a given text-size is reasonably consistent cross-browser (e.g. a negative margin of -3px seems to work at default browser text size pretty well).

It's a kludge, admittedly, but in my testing it work on Windows for IE8, FF, Safari, and Opera. The next thing would be to see how it would work with list-items that were image-based and specified widths. I would think it would be even safer.

Avangelist

comment number
date
April 12, 2010 10:51

Great, except inline-block doesn't work in a few browsers, so the opening statement of 'ready for every day use' is wrong.

It wont be ready fully until all browsers are compliant with CSS3 which hasn't been finished yet.

Isn't there talk of some sort of box display being introduced as well which would remove the need for inline-block, or is meant to replace inline-block?

Niels Matthijs

comment number
date
April 12, 2010 11:00

Great, except inline-block doesn't work in a few browsers, so the opening statement of 'ready for every day use' is wrong.

Which browsers are you talking about?
And inline-block is a css2.1 property value, so I think it's unrelated to any css3 developments.

it's possible to use negative horizontal margins on your LIs

You have a point there, although it sounds a little too dirty for my liking. Especially if you need your page to zoom (em-design) consistently cross-browser. But as a quick fix, good remark.

Kev Adamson

comment number
date
April 12, 2010 11:08

I use "inline-block" quite a lot on list elements - for example: pagination. The white-space issue can be resolved by simply ensuring each start and end tag "touch". For example:

<li>Item 1</li>

<li>Item 2</li>

becomes

<li>Item 1</li><li>item 2</li>

I also set values from "inline-block" to "inline" in ie6 and 7

Luc

comment number
date
April 28, 2010 15:45

I use 'inline-block' all the time. For IE6and IE7 it's just a simple display:inline feeding with condcoms (of course not on inline elements by default). For FF2 there's indeed the moz fix but since FF3 is out for some time now and FF users tend to upgrade quickly i usually don't bother with it. About the white-space problem, there is a trick: simply removing any whitespace between the elements in question, is impractical for two reasons: 1. a lot of dynamically generated content won’t be set up with that sort of issue in mind, and 2. clients entering their own content.

A solution for this is using word-space: give it a value (in px, em, etc) and that’s how it modifies the existing whitespace between words. This counts for space between inline-block elements as well. So if you give the parent of those elements word-spacing: -1em, then it will remove the whitespace (normally 1em) that is between your inline-block elements. But there's a catch: make sure to give the elements themselves word-spacing: normal to reset the spacing for any text inside them, or you’ll get some nasty results. Sadly this solution doesn't work in webkit browsers: Safari and Chrome.

But to fix that, : 1.On the container holding your inline-block elements, give it font-size: 0.

2.Inside the inline-blocks, reset your font-size to its appropriate amount (warning, ems won't work, since 1em of 0 is still 0, so it needs to be reset in pixels. Text will still resize.)

With the font-size trick, all browsers will eliminate the white-space problem.

Dan

comment number
date
June 03, 2010 19:36

Sweet stuff there, Luc. Thanks for sharing your findings. I was thinking about using negative margins with text-related units (ems, exs), so it would scale with the browsers' text zoom. But your word-spacing solution looks more reliable.

EspadaV8

comment number
date
August 19, 2010 00:27

I have found a quick way to fix the spacing issue, but I'm not a big fan or it yet though.

On the parent <ul> you can add {word,letter}-spacing and give it a negative number (when I was testing on my site I found -4px) will pull them in, and then on the <li>'s add {word,letter}-spacing: normal to force it back.

I'm pretty sure that the -4px is completely random and dependent upon the site, so it'd be nice to fine a value that would work anywhere (you could set a larger number than you need, but that can also cause scroll bars to appear).

EspadaV8

comment number
date
August 19, 2010 00:28

LOL, maybe I should've read the comments before posting. Oops.

John

comment number
date
October 28, 2010 15:51

I dislike floats. While I understand their general purpose, they cause sometimes unexpected (to me, at least) behavior, especially when trying to lay out columns within a container.

Suppose I have a container. Now suppose that container has several floated items. At this point, the container has no height. Even though visually the floats appear to be within the container.

Now, add a non-floated block element underneath the floated items and style it red. Something unexpected happens: the entire container becomes red, just like it's non-floated element.

This causes significant problems when you're doing development with a CMS or some other type of dynamic html generation.

Brent Hartmann

comment number
date
December 17, 2010 17:57

For anyone interested in how to make inline blocks in ie7, you need to use the zoom:1 property with *display:inline

http://www.stevenmonetti.com/blog/inline-blocks-ie7

Assad

comment number
date
April 07, 2011 19:41

man you are awesome. This has cleared my mind a lot. Though i am not a CSS person, still this has cleared the concept in my mind. Hats off for you

sandeep

comment number
date
March 10, 2012 08:00

very vivid explanation. nice article..

anon

comment number
date
June 15, 2012 17:05

I just wanted to say that the twitter bird at the bottom of your pages is the creepiest thing ever...

iamkeir

comment number
date
October 24, 2012 10:41

Re point 2), could you not force a new line with the following?

ul li:nth-child(3n)::after {content:"";display:block;}

* required fields

Leave your data
Leave a comment