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="http://www.nczonline.net/" class="button"><strong>Submit</strong></a>
<a href="http://www.nczonline.net/" 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
Richard York says:
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.
Richard York says:
Oh, if you're interested in reading up on it, here's the bug in Bugzilla:
https://bugzilla.mozilla.org/show_bug.cgi?id=9458
Nicholas C. Zakas says:
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).
Julian Turner says:
Have you had a look at this web-site, which may have some other ideas for you:-
http://www.cssplay.co.uk/menus/centered2.html
vic says:
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;
}
Richard York says:
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.
andrew says:
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;}
Nicholas C. Zakas says:
Andrew - thanks for the tip!
kemie says:
a bit belated, but i just read in the bug report- it seems to be fixed. woohoo!
Salvatore Previti says:
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
Neike Taika-Tessaro says:
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.
Stephen says:
Thank you, this saved me a lot of hassle. Much appreciated.
BK says:
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)
Nicholas C. Zakas says:
@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.
Jorge Bucaran says:
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
Jens says:
Firefox sucks at this point, another reason to stick with IE.
vytas says:
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?
No further comments allowed for this posting.