Cross Browser Support for inline-block Styling

I learned a new CSS trick from one of the best insane inventor webdevs I know. The pieces have been out there for some time, it seems, but I hadn’t ever seen this spelled out as simply and elegantly as he did it.

Inline-block layout solves a lot of problems. It lets you do some cool stuff previously thought impossible with CSS. It makes vertical alignment work properly. And sadly, it’s supported pretty badly.

Mozilla doesn’t support inline-block at all, but they have -moz-inline-stack which is about the same. Fair enough, since no one else understands -moz-inline-block, you can just do this:

display:-moz-inline-stack;
display:inline-block;

If you put inline-block after -moz-inline-stack, then Moz will start using the “right” one when it supports it.

IE supports inline-block, but only for elements that are natively inline. So, if you really want to use inline-block, you’re restricted to spans and strongs and ems, when a list or paragraph would perhaps make more semantic sense (and also degrade more nicely for non-CSS users.)

However, if you trigger hasLayout on a block element, and then set it to display:inline, it magically becomes an inline-block in IE! By using the *property hack (which I love so well), you can hide the display:inline from all non-IE browsers effortlessly.

Here’s the code, in all its brief loveliness:

display:-moz-inline-stack;
display:inline-block;
zoom:1;
*display:inline;

From there, it pays to learn a thing or two about the vertical-align property. It lets you do lovely things like this.

Benefits

Inline block elements can be vertically centered like display:table-cell, but they wrap when they get to the end of their parent. Also, it’s supported across browsers using this hack, whereas display:table-cell is not supported in IE.

This technique allows for some very interesting layout approaches that would have required a lot of very tricky use of floats previously.

Caveats

If an element is inside of an inline block, and lies outside the line box, then it won’t be clickable in Mozilla. Give the child element position:relative to correct the problem.

Elements treated this way will have hasLayout set in MSIE. This is a weird and esoteric aspect of MSIE’s CSS engine that has potentially unforeseen consequences. Beware.

If an IMG element is directly inside an inline block element in Mozilla, it will stretch to the full width of that element. Wrap all IMG tags in a block-level container element to avoid the problem.

Since inline block elements wrap and flow like inline content, that means that they also respect white space like words on a page would. That is, if there is *any* whitespace between two inline-block elements, then a single space will be added between two inline-block elements. If this causes a problem, you can either remove the whitespace or comment it out like so:

</div><!--
--><div>

All in all, the caveats are pretty easy to work around, and the benefits allow for some really cool stuff that would be almost impossible or very difficult otherwise.

The 2 Faces of vertical-align

In a classic CSS blunder, vertical-align can mean 2 extremely different things, depending on whether an element is display:inline-block or display:table-cell.

table-cell

Align the element’s contents according to the element’s vertical-align property. IE, if the cell’s vertical-align is set to “middle”, then vertically center the element’s contents. The height and position of the element itself is determined by the containing display:table element.

inline-block

Align the element according to the element’s vertical-align property. IE, if the inline-block’s vertical-align is set to “middle”, then the element is vertically centered in the line-block. The height and position of the element’s contents are determined by the standard block-level flow rules.

While I personally believe that this was a stupendously bad and confusing approach to take, I believe that the reasoning comes from backwards compatibility. Inline blocks emulate the behavior of the IMG tag, and the vertical-align CSS property thus mimics the old valign attribute. Table cells emulate the behavior of the TD tag, and the vertical-align CSS property thus mimics the behavior of the valign attribute on TDs. In other words, in this way, CSS faithfully reproduces the sloppy errors of HTML. It would have been better to use two different properties to achieve this effect; after all, vertical-align:baseline hardly makes sense for table cells. Perhaps the inline-block type of vertical alignment would have been better called “line-position” or some such, since it is less like a vertical version of the text-align property.

But, you write code with the language you have, not the language you wish you had, and CSS is what it is, at least for the foreseeable future.

Recently, I had to achieve an effect that was extremely tricky by standard methods, but extremely easy using tables. I decided to test out a display:table approach, and then try to hack it into place for IE, since it is the only browser that does not support this approach.

The result uses a fairly large number of DIVs, but still fewer than the straight table approach, and without the semantic rubble of tables. The dialog is vertically and horizontally centered, but if you resize the viewport too small, the dialog will not be hidden permanently, due to the “collapse to fit” nature of the table display style. Doing this will an inline-block would have been quite a bit more difficult.

For IE, I used the 50/50 hack. Create a position:absolute element at top:50%. Then, create a position:relative child at top:-50%. The negative top rule on the position:relative element will be misinterpreted, and result in a vertically centered box. The downside is that IE gets a scrollbar if the viewport is less than twice the height of the dialog. But, that’s a pretty acceptable down side, in my opinion.

Sadly, unlike with display:inline-block, it doesn’t look like there’s any real consistency to support display:table across browsers. (Except, of course, using table tags.) You basically just have to hack something for IE that achieves the same effect, and which approach you use varies on the effect you’re going for. In this case, I exploited an IE positioning bug to achieve vertical centering, but other situations would require different approaches. If you’re doing complex layouts using display:table, which in a perfect world would indeed be a great way to do it, you’re going to have a lot of work cut out for you hacking away at IE.

Let’s pray that IE 8 supports display:table!

23 Comments

  1. [...] Cross Browser Support for inline-block Styling [...]

  2. When running the example page for image labels in Opera on OSX I get the following javascript error:

    hasLayout?
    caption undefined relative
    postamble undefined static
    legend undefined static
    preamble undefined relative
    img undefined static
    figure undefined static

    Also, it seems that Opera has a difficult time rendering the text below the images; when scrolling up and down the page, text will unexpectedly display/disappear.

    Hope this helps :)

  3. Thanks, Peter.

    I had accidentally uploaded a copy of the file that had some debugging code in it. It should be all set now :)

    –i

  4. nice,
    i almost had this working myself but the ie problem i didn’t figure out… thanks!

  5. That was incredible it was three days that i was searching for a solution.thanks thanks thanks.

  6. I’ve been searching all night for a solution to a nested inline-block problem I *was* having (but am no more, thanks to your excellent post). All the best to you, my friend!

  7. Very cool. Thanks for posting this information!

  8. http://p.jabba.expotv.com/make/special_promotions

    its messing up in FF2. It’s stretching the image for some reason. anyone getting the same problem?

  9. @pjai

    Wrap your images in a div or span, and then put the styles on the wrapper instead of on the img directly.

    FF2 does odd things with putting -moz-inline-stack on images.

  10. but the style isn’t on the img tag. it is on the wrapper. dunno why its so hard to do center align inline-block elements.

  11. The point is just that you need another wrapper, like this.

    If <img> is within a -moz-inline-stack element, it’ll get borked.

  12. [...] Google,结果还真给我找到了。在这篇文章中指出,如果你首先触发 IE 的 hasLayout,然后再设置它的 [...]

  13. Thanks a lot for this tip!

  14. let’s see… let me try to think of the right way to say this…
    YUUUUUUU ROCKKKKKK!
    I wouldn’t have figured this out on my own and you’ve done more than save me time; you’ve made something possible that I couldn’t have done otherwise. Big ups to you.

  15. very handy. thanks!

  16. I also noticed that -moz-inline-stack doesn’t play well with events. Specifically, a relatively positioned div (with dims) containing an absolute positioned div will not fire the mousedown when the wrapping div is declared -moz-inline-stack. I’m sure there are other issues as well.

    I hope FF2 drops off A grade soon (in favor of FF3).

  17. [...] Но както винаги IE има малки проблеми. Оказва се, че display:inline-block работи само за елементи, които обикновенно са inline. За да станат li елементите inline-block в IE се налага лек [...]

  18. Your article is one of the best I’ve seen about this problem. Many others use browser JavaScript exceptions, which seemed unnecessary. Thanks so much! I’ll keep this in my “toolbox.”

  19. Superb!!! Thank you!!!

  20. Many thanks for a great post. I had been tearing my hair out trying to got this to work on my blog theme.

  21. Great tip! Thanks for the post.

  22. I was having trouble with non-clickable links and multiple divs overlapping with this method (FireFox 2 browsers and others..)

    Tried a few other -moz-inline-* alternatives and eventually found this worked out great as another solution:

    .test {
    display:-moz-inline-box;
    display:inline-block;
    -moz-box-orient: vertical;
    zoom:1;
    *display:inline;
    }

    Have tested the layout via browsershots.org and it looks to be 100% compatible with all browsers. I can’t test clickable links on all, though it is working on FireFox 2.0.

    Cheers.

  23. Great article, helped me sort out picture gallery, display: inline worked ok but wouldn’t give me any space on the line below, inline-block did but not in internet explorer your hack solved the problem. Like your typography as well…

  24. it works too good…. thanks for the hack!

  25. WOW, thank you!! Nice explanation for this, worked great!

Post a Comment

Post Friendly.