Pain with inline-block

Today I found myself wanting to format a link to look like a button. If I only needed one button, I could just set the link’s display to block and be done with it, but I needed two. Further, they needed to be side-by-side. I figured it wouldn’t be a problem because I could use inline-block instead.

The inline-block display is a wonderful state that creates a box inline. Where regular inline displays don’t allow you to set width, height, padding, or margin, inline-block displays allow all of that without the other characteristics of a block-level element. Perfect solution, right? Except for one slight problem: it’s not supported in Firefox.

Safari and Opera support inline-block; Internet Explorer supports inline-block only on elements whose native display is inline. But what about Firefox?

As it turns out, Firefox supported an alternative called -moz-inline-block at one time, but it stopped working in Firefox 1.5. I found some some references suggesting to use -moz-inline-box instead, however, that form of display doesn’t have proper text wrapping and doesn’t support text-align. So, after bending the ear of Matt Sweeney (one of the YUI developers), I was finally able to come up with a solution. The HTML code looks like this:

<a href="https://humanwhocodes.com/" class="button"><strong>Submit</strong></a>
<a href="https://humanwhocodes.com/" class="button"><strong>Cancel</strong></a>

The CSS code is:

a.button {
    background-color: silver;
    border: 1px solid black;
    color: #000;
    display: inline-block;
    display: -moz-inline-stack;
    min-width: 100px;
    _width: 100px;
    padding: 5px;
    text-decoration: none;
}

a.button strong {
    text-align: center;
    display: block;
}

So what’s going on here? There are two display declarations, the first being inline-block and the second being -moz-inline-stack. If a browser properly supports inline-block and CSS, then it will only obey the first declaration. However, since Firefox doesn’t support inline-block, it ignores the first declaration and goes on to the second. Even though Internet Explorer will read both, it will ignore the second because it doesn’t understand the value (Safari and Opera will read only the first one).

The second rule enables proper text wrapping and text alignment inside of the link. Using -moz-inline-stack is the only way that this will work; using -moz-inline-box or -moz-inline-grid won’t work at all. So the inner element (in this case <strong/>), must be set to block in order for text-align to be valid. Now this works in all four browsers…and it only took one day to figure out. Hopefully Firefox will properly implement inline-block soon.

Comments

  1. Richard York

    Isn't the underscore hack dead in the water in IE7?

    Also, the vendor-specific -moz- properties can and do change occasionally, since the majority of them are features of Mozilla XUL. So be warned that they can change in future releases without notice.

    I was just reading up on inline-block in Bugzilla the other day, it seems promising that it might make it into Firefox 3.0.

  2. Richard York

    Oh, if you're interested in reading up on it, here's the bug in Bugzilla:

    https://bugzilla.mozilla.or...

  3. Nicholas C. Zakas

    Richard - yes the underscore hack is dead in IE7, that's why I'm using it. IE7 supports min-width finally, so I don't want to use width in that case.

    Also, I'm aware that vendor-specific extensions can change in the future. I'm banking on the fact that you pointed out: inline-block may make it into Firefox 2.0 (I assume that's what you meant).

  4. Julian Turner

    Have you had a look at this web-site, which may have some other ideas for you:-

    http://www.cssplay.co.uk/me...

  5. vic

    Maybe doesn't work like you want in all aspect, but i already use this for making my links look like small buttons.

    .link_button {
    display: inline; width: auto;
    font-family: sans-serif; font-size: 10px;
    padding: 1px 3px 1px 3px;
    line-height: 20px;
    border: 1px solid #444;
    background-image: url(img/bg.jpg);
    background-color: #E3E3E3;
    text-decoration:none;
    color: black;
    cursor: pointer;
    }
    .link_button:hover {
    text-decoration:none;
    color: #000055;
    background-color: #F3F3F3;
    background-image: url(img/bg.jpg);
    background-position: bottom left;
    border: 1px solid darkorange;
    }

  6. Richard York

    Doh! I did realize that sometime after I read your post. Parsing hacks still feel icky to me though. But, hey, it works, right? :-)

    No, I did mean Firefox 3.0. Firefox 2.0, as far as I know, has no new CSS features, just new scripting features, as I'm sure you already know. 3.0 is code-named "minefield", you can get a copy off of the Mozilla FTP servers.

  7. andrew

    Fantastic post! This has been the bane of my life today :)
    One point though - I had to write two style declarations otherwise IE got confused by the Mozilla style

    i.e.
    a {width:130px; display:inline-block; margin:0 5px;}
    a{display:-moz-inline-stack;}

    NOT
    a {width:130px; display:inline-block; display:-moz-inline-stack; margin:0 5px;}

  8. Nicholas C. Zakas

    Andrew - thanks for the tip!

  9. kemie

    a bit belated, but i just read in the bug report- it seems to be fixed. woohoo!

  10. Salvatore Previti

    You can try also : -moz-groupbox : this helped me with a problem i had with vertical centering and inline-block that doesn't work on firefox.

    TEXT BEFORE -

    <span style="vertical-align: middle; display: -moz-groupbox; display: inline-block;">
    xxx <br />
    yyy <br />
    zzz <br />
    </span>

    - TEXT AFTER

  11. Neike Taika-Tessaro

    Excellent entry, tons helpful, even though the ...-stack variant didn't actually work for me (I settled for ...-box, though as you rightly observe, it refuses to text-align).

    Instead of using the underscore hack, you could also try IE conditional comments (<!--[if IE]><![endif]-->). Give it a google - they make hacks almost obsolete. The keyword here is 'almost' - but it's cleaner than fixing false behaviour by depending on false behaviour, in my opinion.

    Coincidentially, IE simply *treats* inline as inline-block. That means you don't have to worry about natively-block-display elements... you can just tell IE to "display: inline;". That being said, I currently can't vouch for IE7, since I rarely develop on it.

    Thanks again for the great entry! Very helpful.

  12. Stephen

    Thank you, this saved me a lot of hassle. Much appreciated.

  13. BK

    do it in the other order:
    {display: -moz-inline-box; display: inline-block;}
    That way, other browsers will degrade gracefully to the second rule, and once inline-block is implemented in firefox, it will use inline block too (i.e. when 3.0 comes out)

  14. Nicholas C. Zakas

    @BK - That won't degrade correctly because, as far as I know, -moz-inline-box will still be supported in Firefox 3, which means the second property will be ignored and the incorrect style applied.

  15. Jorge Bucaran

    Hi,

    Thanks for the tip, I am not a fan of creepy hacks like these but I needed to align some divs with a background image that is presented instead of text links and this worked magic!

    Regards, Jorge

  16. Jens

    Firefox sucks at this point, another reason to stick with IE.

  17. vytas

    i ran into very strange FF issue - basically, I'm using -moz-display-block on span, which is in the table cell. everything works fine untill cell doesn't have align property - after that inline block is ignored. how weir is that?

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.